/*
 * 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_linestitch.h"
#include "curves/OE_pointcurve.h"
#include "curves/OE_joincurve.h"
#include "curves/OE_subcurve.h"
#include <iostream>

OE_linestitch::OE_linestitch() : curve(nullptr), reverse(false), len(1), width(1),
    pattern(nullptr), patternSteps(1), xOffset(0), yOffset(0)
{
}

/*
OE_linestitch::OE_linestitch(OE_thread* thread, float len, float width, OE_pattern* pattern)
{
	curve = new OE_joincurve();
	curve->addDependency(this);
	this->len = len;
	this->width = width;
	this->thread = thread;
	this->pattern=pattern;
	setNeedRefresh();
}*/

OE_linestitch::OE_linestitch(OE_thread* thread, float len, float width, OE_pattern* pattern,
                             unsigned patternSteps, float xOffset, float yOffset) : OE_linestitch()
{
	curve = new OE_joincurve();
	curve->addDependency(this);
	this->len = len;
	this->width = width;
	this->pattern = pattern;
	this->thread = thread;
	this->xOffset = xOffset;
	this->yOffset = yOffset;
	this->patternSteps = patternSteps;

	setNeedRefresh();
}

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

	archive->set_type_name("OE_linestitch");
	archive->value("curve", curve);
	archive->value("reverse", reverse);
	archive->value("len", len);
	archive->value("width", width);
	archive->value("pattern", pattern);
	archive->value("patternSteps", patternSteps);
	archive->value("xOffset", xOffset);
	archive->value("yOffset", yOffset);
}


OE_linestitch::~OE_linestitch()
{
	std::list<OE_subcurve*>::iterator i = curve->curves.begin();
	while (i != curve->curves.end())
	{
		(*i)->removeDependency(curve);
		delete *i;
		i++;
	}
	if (curve)
	{
		delete curve;
	}
}

/*
void  OE_linestitch::setCurve(OE_curve* curve)
{
	if (this->curve)this->curve->removeDependency(this);
	this->curve = curve;
	curve->addDependency(this);
	setNeedRefresh();
}
*/

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

void OE_linestitch::setWidth(float width)
{
	this->width = width;
	setNeedRefresh();
}

void OE_linestitch::setPattern(OE_pattern* stitch)
{
	pattern = stitch;
	setNeedRefresh();
}

void OE_linestitch::setXOffset(float offset)
{
	xOffset = offset;
	setNeedRefresh();
}
void OE_linestitch::setYOffset(float offset)
{
	yOffset = offset;
	setNeedRefresh();
}

void OE_linestitch::setReverse(bool reverse)
{
	this->reverse = reverse;
	setNeedRefresh();
}

OE_joincurve* OE_linestitch::getJoincurve()
{
	return curve;
}

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

float OE_linestitch::getWidth()
{
	return width;
}

OE_pattern* OE_linestitch::getPattern()
{
	return pattern;
}

float OE_linestitch::getXOffset()
{
	return xOffset;
}
float OE_linestitch::getYOffset()
{
	return yOffset;
}

bool OE_linestitch::getReverse()
{
	return reverse;
}

bool OE_linestitch::check()
{
	return curve && curve->check() && pattern && len;
}

//OE_curve::refresh(float dpi)
/*void OE_linestitch::refresh()
{

}*/

void OE_linestitch::refresh(float dpi, bool force)
{
	if (!check() || !(needRefresh && force))
	{
		return;
	}
	curve->refresh( dpi, force);
	if (curve->getNpts()>3)
	{
		std::vector<vector_2dt> tmpCurvePts;

		tmpCurvePts = curve->discretizeRegular(len/patternSteps);
		std::vector<vector_2d> curvePts(tmpCurvePts.begin(), tmpCurvePts.end());

		if (curvePts.size()<2)
		{
			return;
		}

		//calcul des normales
		std::vector<vector_2d> normalPts;
		vector_2d tmpNormal;
		vector_2d normal;
		for(unsigned i=0; i<curvePts.size()-1; i++)
		{
			normal = curvePts.at(i+1)-curvePts.at(i);
			normal.turnRight();
			if (i==0)
			{
				tmpNormal = normal;
			}
			tmpNormal =tmpNormal + normal;
			tmpNormal.normalize();
			normalPts.push_back( tmpNormal*width);

			tmpNormal = normal;
		}
		tmpNormal.normalize();
		normalPts.push_back( tmpNormal*width);

		std::vector<vector_2d> outPts = warpStitch(curvePts, normalPts, true, pattern, patternSteps, xOffset, yOffset-pattern->defaultOffset);

		stitchPostProcess(outPts);
	}
	needRefresh = false;
}

void OE_linestitch::delDependency(OE_base* object)
{
	if (curve == object)
	{
		curve = 0;
	}
}

void OE_linestitch::refreshDependency()
{
	if (curve)
	{
		curve->addDependency(this);
		curve->refreshDependency();
	}
}
