/*
 * 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.
 *
 */

#pragma once

#include "curves/OE_curve.h"
#include "stitchs/OE_stitchs.h"
#include "curves/OE_joincurve.h"
#include "curves/OE_pointcurve.h"
#include "OE_pattern.h"

namespace Pakal { class  Archive; }

class OE_fillstitch : public OE_stitchs
{
	public:
		OE_fillstitch();
		OE_fillstitch(OE_thread* thread, float len, float width, OE_pattern* pattern);
		~OE_fillstitch();

		virtual void persist(Pakal::Archive* archive) override;

		virtual bool check();

		//virtual void refresh();

		virtual void refresh(float dpi, bool force = false);

		void setLen(float len);
		void setWidth(float width);
		void setPattern(OE_pattern* stitch);
		void initGridControl();
		void refreshCurves();

		OE_joincurve* getJoincurve();
		std::vector<vector_2d> getGridControl();
		std::vector<OE_pointcurve> getCurveControl();
		vector_2d getGridControlPoint(int index);
		void setGridControlPoint(int index, vector_2d point);

		virtual void move(vector_2d offset);
		virtual void scale(vector_2d ratio, vector_2d pos);

		float getLen();
		float getWidth();
		OE_pattern* getPattern();

		void delDependency(OE_base * object);
		virtual void refreshDependency();

	protected:
		struct intersection
		{
			vector_2d pt;
			bool cross;
			bool xcross;
			float gridYPos;
			float gridXPos;
			int contourSegment;
			int cutIndex;
			intersection(vector_2d _pt, bool _cross, bool _xcross, float _gridYPos, int _contourSegment,float _gridXPos) : cutIndex(-1)
			{
				pt = _pt;
				cross = _cross;
				xcross = _xcross;
				gridYPos = _gridYPos;
				contourSegment = _contourSegment;
				gridXPos = _gridXPos;
			}
			intersection() : cutIndex(-1) {}
		};

		struct fillPatch;

		struct cut
		{
			int intersect1;
			int intersect2;
			cut(int _intersect1, int _intersect2);
			fillPatch* upPatch;
			fillPatch* downPatch;
			std::vector<int> contours;
		};

		struct contour_segment
		{
			int minXCell, minYCell, maxXCell, maxYCell, cutStart, cutEnd;
			std::vector<intersection> intersections;
			contour_segment() : minXCell(-1), cutEnd(-1) {}
			void addIntersection(intersection intersection);
		};

		struct stitch_line
		{
			int yCell, minXCell, maxXCell;
			std::vector<intersection> intersections;
			stitch_line() :yCell(-1), minXCell(-1), maxXCell(-1) {}
			void addIntersection(intersection intersection);
		};

		struct fillPatch
		{
			int minXCell, minYCell, maxXCell, maxYCell;
			bool invertRow;
			bool invertCol;
			std::vector<unsigned> contour_segments;
			std::vector<int> cuts;
			std::vector<stitch_line> stitch_lines;
			fillPatch();
			void addSegment(contour_segment _segment, unsigned _id);
			void addCut(int cut);
			std::vector<vector_2d> patchStitches;
		};

		OE_joincurve* curve;
		bool reverse;
		float len;
		float width;
		unsigned gridXSize;
		unsigned gridYSize;
		OE_pattern* pattern;
		float xOffset;
		bool initGrid;

		std::vector<vector_2d> gridControl;
		std::vector<OE_pointcurve> curveControl;


		std::vector<vector_2d> traceContour(std::vector<intersection> intersections, int intersectionsStart);
		std::vector<std::vector<vector_2d>> generateGrid(float precision);
		bool findIntersections(const std::vector<vector_2dt> curvePts, const std::vector<std::vector<vector_2d>> gridPts, std::vector<OE_fillstitch::intersection> &intersections, std::vector<int> &inflexions);
		bool findCuts( std::vector<int> inflexions, std::vector<OE_fillstitch::intersection> &intersections, std::vector<cut> &cuts);
		bool findPatchs(const std::vector<OE_fillstitch::intersection> intersections, std::vector<cut> &cuts, std::vector<contour_segment> &segments, std::vector<fillPatch> &patchs);
		bool generateStitchLines(std::vector<contour_segment> segments, fillPatch &patchs);
		bool generateStitches(const std::vector<std::vector<vector_2d>> gridPts, fillPatch &patch);

		bool prolongateSegments(std::vector<contour_segment> &segments);
		bool cutStitches( const std::vector<contour_segment> segments, fillPatch &patch);
};
