/*
 * Copyright (c) 2015 Tricoire Sebastien 3dsman@free.fr
 *
 * This software is provided 'as-is', without any express or implied
 * warranty.  In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 * claim that you wrote the original software. If you use this software
 * in a product, an acknowledgment in the product documentation would be
 * appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 * misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 *
 */

#include "stitchs/OE_birailstitch.h"
#include "curves/OE_pointcurve.h"
#include "curves/OE_curve.h"
#include "Archive.h"
#include <iostream>
#include <algorithm>

float OE_birailstitch::defaultLen = 1;

/*
OE_birailstitch::OE_birailstitch()
{
	this->len = defaultLen;
	this->maxLen = defaultMaxlen;
}
*/

OE_birailstitch::OE_birailstitch(OE_thread* thread) :
    reverse1(false), offset1(0), reverse2(false), offset2(0), len(0)
{
	curve1.addDependency(this);
	curve2.addDependency(this);
	this->len = defaultLen;
	this->maxLen = defaultMaxlen;
	this->thread = thread;
	setNeedRefresh();
}

OE_birailstitch::OE_birailstitch(OE_thread* thread, bool reverse1, bool reverse2,
                                 float offset1, float offset2, float len)
{
	curve1.addDependency(this);
	curve2.addDependency(this);
	this->reverse1 = reverse1;
	this->reverse2 = reverse2;
	this->offset1=offset1;
	this->offset2=offset2;

	this->thread = thread;

	this->len = len;
	setNeedRefresh();
}

void OE_birailstitch::persist(Pakal::Archive* archive)
{
	OE_stitchs::persist(archive);

	archive->set_type_name("OE_birailstitch");
	archive->value("curve1", curve1);
	archive->value("reverse1", reverse1);
	archive->value("offset1", offset1);
	archive->value("curve2", curve2);
	archive->value("reverse2", reverse2);
	archive->value("offset2", offset2);
	archive->value("len", len);
}

OE_birailstitch::~OE_birailstitch()
{
	std::list<OE_subcurve*>::iterator i = curve1.curves.begin();
	while (i != curve1.curves.end())
	{
		(*i)->removeDependency(&curve1);
		delete *i;
		i++;
	}
	i = curve2.curves.begin();
	while (i != curve2.curves.end())
	{
		(*i)->removeDependency(&curve2);
		delete *i;
		i++;
	}
}

void OE_birailstitch::setReverse1(bool reverse)
{
	reverse1=reverse;
	setNeedRefresh();
}
void OE_birailstitch::setOffset1(float offset)
{
	offset1=offset;
	setNeedRefresh();
}

void OE_birailstitch::setReverse2(bool reverse)
{
	reverse2=reverse;
	setNeedRefresh();
}
void OE_birailstitch::setOffset2(float offset)
{
	offset2=offset;
	setNeedRefresh();
}

void OE_birailstitch::setLen(float len)
{
	this->len = len;
	setNeedRefresh();
}

OE_joincurve* OE_birailstitch::getJoincurve1()
{
	return &curve1;
}
bool OE_birailstitch::getReverse1()
{
	return reverse1;
}
float OE_birailstitch::getOffset1()
{
	return offset1;
}

OE_joincurve* OE_birailstitch::getJoincurve2()
{
	return &curve2;
}
bool OE_birailstitch::getReverse2()
{
	return reverse2;
}
float OE_birailstitch::getOffset2()
{
	return offset2;
}

float OE_birailstitch::getLen()
{
	return len;
}

bool OE_birailstitch::check()
{
	return len;
}

//void OE_birailstitch::refresh(){}

void OE_birailstitch::refresh(float dpi, bool force)
{
	if (!check() || !(needRefresh && force))
	{
		return;
	}

	curve1.refresh(dpi, force);
	curve2.refresh(dpi, force);

	std::vector<vector_2dt> curve1Pts;
	std::vector<vector_2dt> curve2Pts;

	if (curve1.getNpts()>3 && curve2.getNpts()>3)
	{
		float curve1len = curve1.getLength(0.001);
		float curve2len = curve2.getLength(0.001);
		float medlen = (curve1len+curve2len)/2;

		if (curve1len==0 || curve2len==0)
		{
			return;
		}

		curve1Pts = curve1.discretizeRegular(len*(curve1len/medlen));
		curve2Pts = curve2.discretizeRegular(len*(curve2len/medlen));

		if (reverse1)
		{
			std::reverse(curve1Pts.begin(),curve1Pts.end());
		}
		if (reverse2)
		{
			std::reverse(curve2Pts.begin(),curve2Pts.end());
		}

		if ((curve1Pts.size()<2) || (curve2Pts.size()<2) || (curve1Pts.size()!=curve2Pts.size()))
		{
			return;
		}

		//calcul des normales

		std::vector<vector_2d> normal1Pts = normals(curve1Pts);
		std::vector<vector_2d> normal2Pts = normals(curve2Pts);

		std::vector<vector_2d> outPts;
		vector_2d  vec1, vec2;
		for(unsigned i=0; i<curve1Pts.size()-1; i++)
		{
			outPts.push_back(curve1Pts.at(i).v+ normal1Pts.at(i)*offset1);
			outPts.push_back(curve2Pts.at(i).v+ normal2Pts.at(i)*-offset2);
		}

		stitchPostProcess(outPts);
	}
	needRefresh = false;
}

void OE_birailstitch::refreshDependency()
{
	curve1.refreshDependency();
	curve1.addDependency(this);
	curve2.refreshDependency();
	curve2.addDependency(this);
}

