//+------------------------------------------------------------------+
//|                        "Gann High-Low_Cross_Dashboard_With_Alert |
//|                               Copyright © 2017, Gehtsoft USA LLC | 
//|                                                                  |
//+------------------------------------------------------------------+

#property indicator_chart_window

extern string _____________________MaSetting;
extern int      Lb                       = 9;
extern int      CloseBarEma              = 0;
extern string   Comment1                 = "- Comma Separated Pairs - Ex: EURUSD,EURJPY,GBPUSD - ";
extern string   Pairs                    = "EURUSD,EURJPY,GBPUSD";
extern bool     Include_M1               = true;
extern bool     Include_M5               = true;
extern bool     Include_M15              = true;
extern bool     Include_M30              = true;
extern bool     Include_H1               = true;
extern bool     Include_H4               = true;
extern bool     Include_D1               = true;
extern bool     Include_W1               = true;
extern bool     Include_MN1              = true;
extern color    Labels_Color             = clrWhite;
extern color    Up_Color                 = clrLime;
extern color    Dn_Color                 = clrMagenta;
extern color    Neutral_Color            = clrDarkGray;
extern bool     Sound_Alert              = true;
extern bool     Email_Alert              = false;
input bool      Push_Alert               = true;


string   WindowName;
int      WindowNumber;

class Iterator
{
    int _initialValue;
    int _shift;
    int _current;
public:
    Iterator(int initialValue, int shift)
    {
        _initialValue = initialValue;
        _shift = shift;
        _current = _initialValue - _shift;
    }

    int GetNext()
    {
        _current += _shift;
        return _current;
    }
};

class ICell
{
public:
    virtual void Draw() = 0;
protected:
    void ObjectMakeLabel( string nm, int xoff, int yoff, string LabelTexto, color LabelColor, int LabelCorner=1, int Window = 0, string Font = "Arial", int FSize = 8 )
    {
        ObjectDelete(nm);
        ObjectCreate(nm, OBJ_LABEL, Window, 0, 0);
        ObjectSet(nm, OBJPROP_CORNER, LabelCorner);
        ObjectSet(nm, OBJPROP_XDISTANCE, xoff);
        ObjectSet(nm, OBJPROP_YDISTANCE, yoff);
        ObjectSet(nm, OBJPROP_BACK, false);
        ObjectSetText(nm, LabelTexto, FSize, Font, LabelColor);
        
        
    }
};

class Row
{
    ICell *_cells[];
public:
    ~Row()
    {
        int count = ArraySize(_cells);
        for (int i = 0; i < count; ++i)
        {
            delete _cells[i];
        }
    }

    void Draw()
    {
        int count = ArraySize(_cells);
        for (int i = 0; i < count; ++i)
        {
            _cells[i].Draw();
        }
    }

    void Add(ICell *cell)
    {
        int count = ArraySize(_cells);
        ArrayResize(_cells, count + 1);
        _cells[count] = cell;
    }
};

//draws nothing
class EmptyCell : public ICell
{
public:
    virtual void Draw()
    {
        //do nothing
    }
};

//draws a label
class LabelCell : public ICell
{
    string _id;
    string _text;
    int _x;
    int _y;
public:
    LabelCell(const string id, const string text, const int x, const int y)
    {
        _id = id;
        _text = text;
        _x = x;
        _y = y;
    }

    virtual void Draw()
    {
        ObjectMakeLabel(_id, _x, _y, _text, Labels_Color, 1, WindowNumber, "Arial", 12);
    }
};

class ValueCell : public ICell
{
    string _id;
    int _x;
    int _y;
    string _symbol;
    int _timeframe;
    datetime _lastDatetime;
public:
    ValueCell(const string id, const int x, const int y, const string symbol, const int timeframe)
    {
        _id = id;
        _x = x;
        _y = y;
        _symbol = symbol;
        _timeframe = timeframe;
    }

    virtual void Draw()
    {
        int direction = GetDirection();
        SendNotifications(direction);
        ObjectMakeLabel(_id, _x, _y, GetDirectionSymbol(direction), GetDirectionColor(direction), 1, WindowNumber, "Arial", 10);
    }

private:
    string GetTimeframe()
    {
        switch (_timeframe)
        {
		
		    case PERIOD_M1:
                return "M1";
            case PERIOD_M5:
                return "M5";
            case PERIOD_D1:
                return "D1";
            case PERIOD_H1:
                return "H1";
            case PERIOD_H4:
                return "H4";
            case PERIOD_M15:
                return "M15";
            case PERIOD_M30:
                return "M30";
            case PERIOD_MN1:
                return "MN1";
            case PERIOD_W1:
              return "W1";  
               
                
        }
         return 0;
    }

    void SendNotifications(const int direction)
    {
        datetime currentTime = iTime(_symbol, _timeframe, 0);
        if (_lastDatetime == currentTime)
            return;

        _lastDatetime = currentTime;
        if (direction == 0)
            return;
            
        string tf = GetTimeframe();
        string alert_Subject = "HiLo Cross on " + _symbol + "/" + tf;
        string alert_Body = "HiLo Cross on " + _symbol + "/" + tf;
        
        if (Sound_Alert) Alert(alert_Body);
        if (Email_Alert) SendMail(alert_Subject, alert_Body);
        if (Push_Alert)  SendNotification(alert_Body);
    }

    int GetDirection()
    {
        double emahi = iMA(_symbol,_timeframe,Lb,0,MODE_EMA,PRICE_HIGH, CloseBarEma+1);
        double emalo = iMA(_symbol,_timeframe,Lb,0,MODE_EMA,PRICE_LOW,  CloseBarEma+1);
        double cl    = iMA(_symbol,_timeframe,1,0,MODE_EMA,PRICE_CLOSE, CloseBarEma);
        
        if (cl > emahi)
        {
            return 1;
        }
        if (cl < emalo)
        {
            return -1;
        }
        return 0;
    }

    color GetDirectionColor(const int direction)
    {
        if (direction == 1)
        {
            return Up_Color;
        }
        else if (direction == -1)
        {
            return Dn_Color;
        }
        return Neutral_Color;
    }

    string GetDirectionSymbol(const int direction)
    {
        if (direction == 1)
        {
            return "Up";
        }
        else if (direction == -1)
        {
            return "Dn";
        }
        return "-";
    }
};

Row *rows[];

int GetTimeframesCount()
{
    int count = 0;
	
	if (Include_M1)
        count++;
		
    if (Include_M5)
        count++;
    if (Include_M15)
        count++;
    if (Include_M30)
        count++;
    if (Include_H1)
        count++;
    if (Include_H4)
        count++;
    if (Include_D1)
        count++;
    if (Include_W1)
        count++;
    if (Include_MN1)
        count++;
    return count;
}

int init()
{
    WindowName = "Gann High-Low_Cross_Dashboard_With_Alert 1";
    IndicatorShortName(WindowName);

    int Original_x = 1000;
    string sym_arr[];
    split(sym_arr, Pairs, ",");
    int sym_count = ArraySize(sym_arr);

    int timeframes_count = GetTimeframesCount();
    ArrayResize(rows, timeframes_count + 1);
    for (int i = 0; i <= timeframes_count; ++i)
    {
        rows[i] = new Row();
    }
    rows[0].Add(new EmptyCell());
    Iterator yIterator(50, 30);
    for (i = 0; i < sym_count; i++)
    {
        rows[0].Add(new LabelCell(sym_arr[i] + "_Name", sym_arr[i], Original_x + 80, yIterator.GetNext()));
    }

    int currentCell = 1;
    Iterator xIterator(Original_x, -120);
	
	  if (Include_M1)
    {
        int m1_x = xIterator.GetNext();
        rows[currentCell++].Add(new LabelCell("M1_Label", "M1", m1_x, 20));
        Iterator yIterator1(50, 30);
        for (i = 0; i < sym_count; i++)
        {
            rows[currentCell - 1].Add(new ValueCell(sym_arr[i] + "_M1", m1_x, yIterator1.GetNext(), sym_arr[i], PERIOD_M1));
        }
    }
	
	
    if (Include_M5)
    {
        int m5_x = xIterator.GetNext();
        rows[currentCell++].Add(new LabelCell("M5_Label", "M5", m5_x, 20));
        Iterator yIterator5(50, 30);
        for (i = 0; i < sym_count; i++)
        {
            rows[currentCell - 1].Add(new ValueCell(sym_arr[i] + "_M5", m5_x, yIterator5.GetNext(), sym_arr[i], PERIOD_M5));
        }
    }
    if (Include_M15)
    {
        int m15_x = xIterator.GetNext();
        rows[currentCell++].Add(new LabelCell("M15_Label", "M15", m15_x, 20));
        Iterator yIterator15(50, 30);
        for (i = 0; i < sym_count; i++)
        {
            rows[currentCell - 1].Add(new ValueCell(sym_arr[i] + "_M15", m15_x, yIterator15.GetNext(), sym_arr[i], PERIOD_M15));
        }
    }
    if (Include_M30)
    {
        int m30_x = xIterator.GetNext();
        rows[currentCell++].Add(new LabelCell("M30_Label", "M30", m30_x, 20));
        Iterator yIterator30(50, 30);
        for (i = 0; i < sym_count; i++)
        {
            rows[currentCell - 1].Add(new ValueCell(sym_arr[i] + "_M30", m30_x, yIterator30.GetNext(), sym_arr[i], PERIOD_M30));
        }
    }
    if (Include_H1)
    {
        int h1_x = xIterator.GetNext();
        rows[currentCell++].Add(new LabelCell("H1_Label", "H1", h1_x, 20));
        Iterator yIteratorH1(50, 30);
        for (i = 0; i < sym_count; i++)
        {
            rows[currentCell - 1].Add(new ValueCell(sym_arr[i] + "_H1", h1_x, yIteratorH1.GetNext(), sym_arr[i], PERIOD_H1));
        }
    }
    if (Include_H4)
    {
        int h4_x = xIterator.GetNext();
        rows[currentCell++].Add(new LabelCell("H4_Label", "H4", h4_x, 20));
        Iterator yIteratorH4(50, 30);
        for (i = 0; i < sym_count; i++)
        {
            rows[currentCell - 1].Add(new ValueCell(sym_arr[i] + "_H4", h4_x, yIteratorH4.GetNext(), sym_arr[i], PERIOD_H4));
        }
    }
    if (Include_D1)
    {
        int d1_x = xIterator.GetNext();
        rows[currentCell++].Add(new LabelCell("D1_Label", "D1", d1_x, 20));
        Iterator yIteratorD1(50, 30);
        for (i = 0; i < sym_count; i++)
        {
            rows[currentCell - 1].Add(new ValueCell(sym_arr[i] + "_D1", d1_x, yIteratorD1.GetNext(), sym_arr[i], PERIOD_D1));
        }
    }
    if (Include_W1)
    {
        int w1_x = xIterator.GetNext();
        rows[currentCell++].Add(new LabelCell("W1_Label", "W1", w1_x, 20));
        Iterator yIteratorW1(50, 30);
        for (i = 0; i < sym_count; i++)
        {
            rows[currentCell - 1].Add(new ValueCell(sym_arr[i] + "_W1", w1_x, yIteratorW1.GetNext(), sym_arr[i], PERIOD_W1));
        }
    }
    if (Include_MN1)
    {
        int mn1_x = xIterator.GetNext();
        rows[currentCell++].Add(new LabelCell("MN1_Label", "MN1", mn1_x, 20));
        Iterator yIteratorMN1(50, 30);
        for (i = 0; i < sym_count; i++)
        {
            rows[currentCell - 1].Add(new ValueCell(sym_arr[i] + "_MN1", mn1_x, yIteratorMN1.GetNext(), sym_arr[i], PERIOD_MN1));
        }
    }

    return(0);
}

int deinit()
{
    ObjectsDeleteAll();
    int i_count = ArraySize(rows);
    for (int i = 0; i < i_count; ++i)
    {
        delete rows[i];
    }
    return(0);
}

int start()
{
    WindowNumber = WindowFind(WindowName);
    int i_count = ArraySize(rows);
    for (int i = 0; i < i_count; ++i)
    {
        rows[i].Draw();
    }

    return(0);
}

void split(string& arr[], string str, string sym) 
{
    ArrayResize(arr, 0);
    int len = StringLen(str);
    for (int i=0; i < len;)
    {
        int pos = StringFind(str, sym, i);
        if (pos == -1)
            pos = len;

        string item = StringSubstr(str, i, pos-i);
        item = StringTrimLeft(item);
        item = StringTrimRight(item);

        int size = ArraySize(arr);
        ArrayResize(arr, size+1);
        arr[size] = item;

        i = pos+1;
    }
}