#ifndef _LINE_FIT_
#define _LINE_FIT_

#include <math.h>
#include <vector>
#include "zlist.h"

struct fit_item
{
	double x,y,xx,xy;
	fit_item();
	fit_item&set(double x,double y);

	void log()const
	{
		printf("x=%.3lf,y=%.3lf,xx=%.3lf,xy=%.3lf\n",x,y,xx,xy);
	}
};

struct card_fit;
struct fit_batch:zlist<fit_item,64>
{
	double xo=0,yo=0;
	std::vector<card_fit*> tool;

public:
	fit_batch();
	~fit_batch();

	int tool_size()const
	{
		return tool.size();
	}
	card_fit&operator[](int i) { return *tool[i]; }
	const card_fit&operator[](int i) const { return *tool[i]; }

	void add_tool(double max_x_span,int min_point);
	void add_tool(double max_x_span,int min_point,int max_point);
	void reset_data();
	double add(double x,double y);
	void replace(double x,double y);
	void remove_bad(int tool_id);

	double x(int index)const;
	double y(int index)const;
	void rlog(int i)const
	{
		rat(i).log();
	}

	void log();
};

struct fit_result
{
	double k,kb,ke,ka;
	double xo,yo;
	int num_point;
	int min_point;
	double max_x_span;

	fit_result();
	fit_result(double max_x_span,int min_point);
	void reset();
	int size()const
	{
		return num_point;
	}

	bool is_valid()const
	{
		return num_point>=min_point;
	}

	void log()
	{
		printf("%5s, %d, k=(%.3f,%.3f,%.3f)\n",is_valid()?"true":"false", size(),k,kb,ke);
	}

	double testk(double x,double y)const;
	double differ_k(double x,double y)const;
};

struct card_fit:fit_result
{
	const fit_batch&d;
	double A = 0, B = 0, C = 0, D = 0;

	card_fit(const fit_batch&d,double _max_x_span,int min_point);
	virtual ~card_fit();
	void reset();

	void dec_(const fit_item&i);
	void add_(const fit_item&i);

	virtual void add_last();
	virtual bool check_x_span();

	virtual bool fit();
};

struct card_fit_stop:card_fit
{
	card_fit_stop(const fit_batch&d_,double _max_x_span,int min_point)
		:card_fit(d_,_max_x_span,min_point)
	{
	}

    virtual void add_last()
	{
	}

	virtual bool fit()
	{
		return false;
	}
};

struct card_fit_lastn:card_fit
{
	int max_point;
	card_fit_lastn(const fit_batch&d_,double _max_x_span,int min_point,int max_point_)
		:card_fit(d_,_max_x_span,min_point)
		,max_point(max_point_)
	{
	}

	bool check_x_span()
	{
		int i=size()-1;
		for(;i>0;i--)
		{
			double off=d(0).x-d(i).x;
			if(off>max_x_span+0.5 || i>=max_point)
			{
				--num_point;
				dec_(d(i));
				continue;
			}

			break;
		}

		return num_point>=min_point;
	}
};

#endif