//=====================================================================
//	Работа с экстремумами на графике:
//=====================================================================

//---------------------------------------------------------------------
#property copyright 	"Dima S., 2010 г."
#property link      	"dimascub@mail.com"
//---------------------------------------------------------------------

//---------------------------------------------------------------------
//	История версий:
//---------------------------------------------------------------------
//	08.11.2010г. - V1.00
//	 - НАЧАЛЬНАЯ ВЕРСИЯ;
//
//	16.11.2010г. - V1.01
//	 - ИЗМЕНЕНО - различные уточнения;
//
//---------------------------------------------------------------------

//---------------------------------------------------------------------
//	Подключаемые библиотеки:
//---------------------------------------------------------------------

#include	<Object.mqh>
#include	<Arrays\List.mqh>
//---------------------------------------------------------------------

//---------------------------------------------------------------------
//	Понятие экстремума:
//---------------------------------------------------------------------
class TExtremum : public CObject
{
private:
	datetime			extr_datetime;																				// дата/время в точке экстремума
	double				extr_price;																						// цена в точке экстремума
	
protected:
	virtual int		Compare(const CObject* _node, int _mode = 0) const;

public:
	void					TExtremum();																					// конструктор
	void					~TExtremum();																					// деструктор
	void					SetExtremum(datetime _time, double _price);						// изменить дату/время и цену в точке экстремума
	void					SetDateTime(datetime _time);													// изменить дату/время в точке экстремума
	void					SetPrice(double _price);															// изменить цену в точке экстремума

public:
	datetime			GetDateTime() const;																	// получить дату/время в точке экстремума
	double				GetPrice() const;																			// получить цену в точке экстремума

public:
  virtual bool	SaveExtremum(string _dt_name, string _p_name);				// сохранить экстремум
  virtual bool	LoadExtremum(string _dt_name, string _p_name);				// считать экстремум
  virtual bool	DeleteExtremum(string _dt_name, string _p_name);			// удалить экстремум
};
//---------------------------------------------------------------------

//---------------------------------------------------------------------
//	Конструктор:
//---------------------------------------------------------------------
void	TExtremum::TExtremum()
{
	this.extr_datetime = 0;
	this.extr_price = 0.0;
}

//---------------------------------------------------------------------
//	Деструктор:
//---------------------------------------------------------------------
void	TExtremum::~TExtremum()
{
}

//---------------------------------------------------------------------
//	Сохранить экстремум (дату/время):
//---------------------------------------------------------------------
bool	TExtremum::SaveExtremum(string _dt_name, string _p_name)
{
	datetime  dt_result = GlobalVariableSet(_dt_name, (double)this.extr_datetime);
	datetime  p_result = GlobalVariableSet(_p_name, (double)this.extr_price);
	if(dt_result != 0 && p_result != 0)
	{
		return(true);
	}

	return(false);
}

//---------------------------------------------------------------------
//	Считать экстремум (дату/время):
//---------------------------------------------------------------------
bool	TExtremum::LoadExtremum(string _dt_name, string _p_name)
{
	double	dt_temp, p_temp;
	bool		result = GlobalVariableGet(_dt_name, dt_temp);
	result &= GlobalVariableGet(_p_name, p_temp);
	if(result != false)
	{
		this.extr_datetime = (datetime)dt_temp;
		this.extr_price = p_temp;
		return(true);
	}

	return(false);
}

//---------------------------------------------------------------------
//	Удалить экстремум:
//---------------------------------------------------------------------
bool	TExtremum::DeleteExtremum(string _dt_name, string _p_name)
{
	bool		result = GlobalVariableDel(_dt_name);
	result &= GlobalVariableDel(_p_name);
	return(result);
}

//---------------------------------------------------------------------
//	Сравнение двух экстремумов по времени:
//---------------------------------------------------------------------
int	TExtremum::Compare(const CObject* _node, int _mode = 0) const
{
	datetime		temp = ((TExtremum*)_node).GetDateTime();
	datetime		curr = this.GetDateTime();
	if(curr > temp)
	{
		return(_mode > 0 ? 1 : -1);
	}
	else if(curr < temp)
	{
		return(_mode > 0 ? -1 : 1);
	}

	return(0);
}

//---------------------------------------------------------------------
//	Изменить дату/время и цену в точке экстремума:
//---------------------------------------------------------------------
void	TExtremum::SetExtremum(datetime _time, double _price)
{
	this.extr_datetime = _time;
	this.extr_price = _price;
}

//---------------------------------------------------------------------
//	Изменить дату/время в точке экстремума:
//---------------------------------------------------------------------
void	TExtremum::SetDateTime(datetime _time)
{
	this.extr_datetime = _time;
}

//---------------------------------------------------------------------
//	Изменить цену в точке экстремума:
//---------------------------------------------------------------------
void	TExtremum::SetPrice(double _price)
{
	this.extr_price = _price;
}

//---------------------------------------------------------------------
//	Получить дату/время в точке экстремума:
//---------------------------------------------------------------------
datetime	TExtremum::GetDateTime() const
{
	return(this.extr_datetime);
}

//---------------------------------------------------------------------
//	Получить цену в точке экстремума:
//---------------------------------------------------------------------
double	TExtremum::GetPrice() const
{
	return(this.extr_price);
}

//---------------------------------------------------------------------
//	Манипуляция экстремумами:
//---------------------------------------------------------------------
class TExtremumList : public CList
{
private:
	string							channel_prefix;																	// имя канала (префикс)
	ENUM_TIMEFRAMES			chart_timeframe;																// тайм-фрейм текущий
	string							chart_symbol;																		// рабочий символ на графике

protected:
	string	MakeDTimeName(int _nmb);																		// получить имя для сохранения/чтения даты/времени экстремума
	string	MakePriceName(int _nmb);																		// получить имя для сохранения/чтения цены экстремума

public:
	void		TExtremumList();																						// конструктор
	void		~TExtremumList();																						// деструктор
	void		SetChannalParams(string _pref, string _symbol = NULL, ENUM_TIMEFRAMES _curr_tf = PERIOD_CURRENT);
	void		AddExtremum(datetime _time, double _price);
	void		DeleteAllExtremum();
	void		SaveExtremumList();
	void		LoadExtremumList();
	int			FindExtremum(datetime _dt);																	// поиск экстремума по заданному времени

public:
	datetime	GetDateTime(int _index);
	double		GetPrice(int _index);
};
//---------------------------------------------------------------------

//---------------------------------------------------------------------
//	Конструктор:
//---------------------------------------------------------------------
void	TExtremumList::TExtremumList()
{
	this.chart_timeframe = PERIOD_CURRENT;
	this.channel_prefix = "";
	this.chart_symbol = NULL;
}

//---------------------------------------------------------------------
//	Деструктор:
//---------------------------------------------------------------------
void	TExtremumList::~TExtremumList()
{
	this.Clear();
}

//---------------------------------------------------------------------
//	Установка общих параметров канала:
//---------------------------------------------------------------------
void	TExtremumList::SetChannalParams(string _pref, string _symbol, ENUM_TIMEFRAMES _curr_tf)
{
	this.channel_prefix = _pref;

	if(_symbol == NULL)
	{
		this.chart_symbol = ChartSymbol();
	}
	else
	{
		this.chart_symbol = _symbol;
	}

	if(_curr_tf == 0)
	{
		this.chart_timeframe = ChartPeriod();
	}
	else
	{
		this.chart_timeframe = _curr_tf;
	}
}

//---------------------------------------------------------------------
//	Удалить все экстремумы из списка:
//---------------------------------------------------------------------
void	TExtremumList::DeleteAllExtremum()
{
	this.Clear();
}

//---------------------------------------------------------------------
//	Добавление экстремума в список с сортировкой по времени:
//---------------------------------------------------------------------
void	TExtremumList::AddExtremum(datetime _time, double _price)
{
//	Создадим экстремум:
	TExtremum*	extr = new TExtremum();
	extr.SetExtremum(_time, _price);

//	Добавим его в список:
	this.Add(extr);

//	Отсортируем:
	this.Sort(1);
}

//---------------------------------------------------------------------
//	Сохранить параметры экстремумов:
//---------------------------------------------------------------------
void	TExtremumList::SaveExtremumList()
{
	int		k = 1;
	TExtremum*	extr = (TExtremum*)(this.GetFirstNode());
	while(extr != NULL)
	{
		extr.SaveExtremum(MakeDTimeName(k), MakePriceName(k));
		k++;
		extr = (TExtremum*)(this.GetNextNode());
	}
}

//---------------------------------------------------------------------
//	Найти экстремум с заданным временем:
//---------------------------------------------------------------------
int		TExtremumList::FindExtremum(datetime _dt)
{
	int		k = 0;
	TExtremum*	extr = (TExtremum*)(this.GetFirstNode());
	while(extr != NULL)
	{
		if(extr.GetDateTime() == _dt)
		{
			return(k);
		}
		extr = (TExtremum*)(this.GetNextNode());
	}
	return(-1);																																// экстремум не найден
}

//---------------------------------------------------------------------
//	Загрузить экстремумы:
//---------------------------------------------------------------------
void	TExtremumList::LoadExtremumList()
{
//	Очистим список от предыдущих экстремумов:
	this.DeleteAllExtremum();

	int		count = GlobalVariablesTotal();
	if(count <= 0)
	{
		return;
	}

	for(int i = (count - 1); i >= 0; i--)
	{
		string	name = GlobalVariableName(i);
		string	dt_name = MakeDTimeName(-1);
		int			index = StringFind(name, dt_name);
		if(index == -1 || index != 0)
		{
			continue;
		}

		string	p_name = MakePriceName(-1) + StringSubstr(name, StringLen(dt_name));
//	Создадим экстремум:
		TExtremum*	extr = new TExtremum();
		extr.LoadExtremum(name, p_name);
		
		this.Add(extr);
	}

//	Отсортируем:
	this.Sort(1);
}

//---------------------------------------------------------------------
//	Получить значение даты/времени экстремума:
//---------------------------------------------------------------------
datetime	TExtremumList::GetDateTime(int _index)
{
	TExtremum*	extr = (TExtremum*)(this.GetNodeAtIndex(_index));
	if(extr != NULL)
	{
		return(extr.GetDateTime());
	}

	return(0);	
}

//---------------------------------------------------------------------
//	Получить значение цены экстремума:
//---------------------------------------------------------------------
double	TExtremumList::GetPrice(int _index)
{
	TExtremum*	extr = (TExtremum*)(this.GetNodeAtIndex(_index));
	if(extr != NULL)
	{
		return(extr.GetPrice());
	}

	return(0);	
}

//---------------------------------------------------------------------
//	Получить имя для сохраниения/чтения даты/времени экстремума:
//---------------------------------------------------------------------
string	TExtremumList::MakeDTimeName(int _nmb)
{
	string	name;
	if(_nmb > 0)
	{
		StringConcatenate(name, this.channel_prefix, "_", this.chart_symbol, "_", this.chart_timeframe, "_DTime_Extr", _nmb);
	}
	else
	{
		StringConcatenate(name, this.channel_prefix, "_", this.chart_symbol, "_", this.chart_timeframe, "_DTime_Extr");
	}
	return(name);
}

//---------------------------------------------------------------------
//	Получить имя для сохраниения/чтения цены экстремума:
//---------------------------------------------------------------------
string	TExtremumList::MakePriceName(int _nmb)
{
	string	name;
	if(_nmb > 0)
	{
		StringConcatenate(name, this.channel_prefix, "_", this.chart_symbol, "_", this.chart_timeframe, "_Price_Extr", _nmb);
	}
	else
	{
		StringConcatenate(name, this.channel_prefix, "_", this.chart_symbol, "_", this.chart_timeframe, "_Price_Extr");
	}
	return(name);
}
//---------------------------------------------------------------------
