using System;
using System.IO;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using cAlgo.Indicators;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.FileSystem)]
    public class CP : Indicator
    {
        #region Parameters

        [Parameter("Show names", DefaultValue = false)]
        public bool Name_Status { get; set; }

        [Parameter("Show more info", DefaultValue = true)]
        public bool Add_info { get; set; }

        [Parameter("Show Doji", DefaultValue = true)]
        public bool Show_Doji { get; set; }

        [Parameter("Show Hammer", DefaultValue = true)]
        public bool Show_Hammer { get; set; }

        [Parameter("MACD Long Cycle", DefaultValue = 26)]
        public int LongCycle { get; set; }

        [Parameter("MACD Short Cycle", DefaultValue = 12)]
        public int ShortCycle { get; set; }

        [Parameter("MACD Signal Periods", DefaultValue = 9)]
        public int Periods { get; set; }

        [Parameter("Doji", DefaultValue = "✝")]
        public string Doji_s { get; set; }
        [Parameter("Hammer", DefaultValue = "☨")]
        public string Hammer_s { get; set; }

        #endregion Parameters

        private MacdHistogram macd;

        private const VerticalAlignment vAlign = VerticalAlignment.Top;
        private const HorizontalAlignment hAlign = HorizontalAlignment.Center;

        private const double n = 0.618;

        private const string UpArrow = "▲";
        private const string DownArrow = "▼";

        private string Pattern_name;

        private double offset;

        private struct Candle
        {
            #region Data

            public double High;
            public double Close;
            public double Open;
            public double Low;

            #endregion Data

            #region Functions

            public bool IsFallCandle()
            {
                if (Close < Open)
                    return true;
                else
                    return false;
            }
            public bool IsRiseCandle()
            {
                if (Open < Close)
                    return true;
                else
                    return false;
            }

            public double Median()
            {
                return (High + Low) / 2;
            }

            #endregion Functions
        }

        private enum PatternType : int
        {
            Doji = 1,
            Hammer = 2
        }

        protected override void Initialize()
        {
            macd = Indicators.MacdHistogram(MarketSeries.Close, LongCycle, ShortCycle, Periods);
            offset = Symbol.PipSize * 5;
        }

        private void DrawText(int index, int _Type)
        {
            var high = MarketSeries.High[index];
            var low = MarketSeries.Low[index];

            int x = index;

            double h_y = high + offset;
            double h_d_y = h_y + offset * 2.5;
            double h_t_y = h_d_y + offset;

            double l_y = low - offset * 2.5;
            double l_d_y = l_y - offset;


            if (TimeFrame == TimeFrame.Minute)
            {
                h_y = high + offset / 2;
                h_d_y = h_y + offset / 2;
                h_t_y = h_d_y + offset;

                l_y = low - offset / 2;
                l_d_y = l_y - offset / 2;
            }



            if (TimeFrame == TimeFrame.Minute15)
            {
                h_y = high + offset / 1.5;
                h_d_y = h_y + offset;
                h_t_y = h_d_y + offset;

                l_y = low - offset * 1.5;
                l_d_y = l_y - offset * 1.1;
            }


            if (TimeFrame == TimeFrame.Hour)
            {
                h_y = high + offset;
                h_d_y = h_y + offset * 3;
                h_t_y = h_d_y + offset;

                l_y = low - offset * 3;
                l_d_y = l_y - offset * 3;
            }

            if (TimeFrame == TimeFrame.Hour4)
            {
                h_y = high + offset;
                h_d_y = h_y + offset * 5;
                h_t_y = h_d_y + offset;

                l_y = low - offset * 5;
                l_d_y = l_y - offset * 5;
            }

            if (TimeFrame == TimeFrame.Daily)
            {
                h_y = high + offset * 3;
                h_d_y = h_y + offset * 12;
                h_t_y = h_d_y + offset;

                l_y = low - offset * 12;
                l_d_y = l_y - offset * 12;
            }

            if (TimeFrame == TimeFrame.Weekly)
            {
                h_y = high + offset * 6;
                h_d_y = h_y + offset * 24;
                h_t_y = h_d_y + offset;

                l_y = low - offset * 24;
                l_d_y = l_y - offset * 24;
            }

            if (TimeFrame == TimeFrame.Monthly)
            {
                h_y = high + offset * 24;
                h_d_y = h_y + offset * 64;
                h_t_y = h_d_y + offset;

                l_y = low - offset * 64;
                l_d_y = l_y - offset * 64;
            }

            string f_ObjName;
            string s_ObjName;

            switch (_Type)
            {
                case (int)PatternType.Doji:

                    f_ObjName = string.Format("Doji {0}", index);
                    s_ObjName = string.Format("Doji | {0}", index);

                    ChartObjects.DrawText(f_ObjName, "Doji", x, h_d_y, vAlign, hAlign, Colors.White);
                    ChartObjects.DrawText(s_ObjName, "\n|", x, h_y, vAlign, hAlign, Colors.White);

                    break;

                case (int)PatternType.Hammer:

                    f_ObjName = string.Format("Hammer {0}", index);
                    s_ObjName = string.Format("Hammer | {0}", index);

                    ChartObjects.DrawText(f_ObjName, "Hammer", x, h_d_y, vAlign, hAlign, Colors.White);
                    ChartObjects.DrawText(s_ObjName, "\n|", x, h_y, vAlign, hAlign, Colors.White);

                    break;

            }
        }

        private void DrawSymbols(int index, int _Type)
        {
            var high = MarketSeries.High[index];
            var low = MarketSeries.Low[index];

            int x = index;

            double h_y = high + offset;
            double h_d_y = h_y + offset * 2.5;
            double h_t_y = h_d_y + offset;

            double l_y = low - offset * 2.5;
            double l_d_y = l_y - offset;


            if (TimeFrame == TimeFrame.Minute)
            {
                h_y = high + offset / 2;
                h_d_y = h_y + offset / 2;
                h_t_y = h_d_y + offset;

                l_y = low - offset / 2;
                l_d_y = l_y - offset / 2;
            }



            if (TimeFrame == TimeFrame.Minute15)
            {
                h_y = high + offset / 1.5;
                h_d_y = h_y + offset;
                h_t_y = h_d_y + offset;

                l_y = low - offset * 1.5;
                l_d_y = l_y - offset * 1.1;
            }


            if (TimeFrame == TimeFrame.Hour)
            {
                h_y = high + offset;
                h_d_y = h_y + offset * 3;
                h_t_y = h_d_y + offset;

                l_y = low - offset * 3;
                l_d_y = l_y - offset * 3;
            }

            if (TimeFrame == TimeFrame.Hour4)
            {
                h_y = high + offset;
                h_d_y = h_y + offset * 5;
                h_t_y = h_d_y + offset;

                l_y = low - offset * 5;
                l_d_y = l_y - offset * 5;
            }

            if (TimeFrame == TimeFrame.Daily)
            {
                h_y = high + offset * 3;
                h_d_y = h_y + offset * 12;
                h_t_y = h_d_y + offset;

                l_y = low - offset * 12;
                l_d_y = l_y - offset * 12;
            }

            if (TimeFrame == TimeFrame.Weekly)
            {
                h_y = high + offset * 6;
                h_d_y = h_y + offset * 24;
                h_t_y = h_d_y + offset;

                l_y = low - offset * 24;
                l_d_y = l_y - offset * 24;
            }

            if (TimeFrame == TimeFrame.Monthly)
            {
                h_y = high + offset * 24;
                h_d_y = h_y + offset * 64;
                h_t_y = h_d_y + offset;

                l_y = low - offset * 64;
                l_d_y = l_y - offset * 64;
            }

            string f_ObjName;
            string s_ObjName;

            switch (_Type)
            {
                case (int)PatternType.Doji:

                    f_ObjName = string.Format("Doji {0}", index);
                    s_ObjName = string.Format("Doji | {0}", index);

                    ChartObjects.DrawText(f_ObjName, Doji_s, x, h_d_y, vAlign, hAlign, Colors.White);
                    ChartObjects.DrawText(s_ObjName, "\n|", x, h_y, vAlign, hAlign, Colors.White);

                    break;

                case (int)PatternType.Hammer:

                    f_ObjName = string.Format("Hammer {0}", index);
                    s_ObjName = string.Format("Hammer | {0}", index);

                    ChartObjects.DrawText(f_ObjName, Hammer_s, x, h_d_y, vAlign, hAlign, Colors.DarkOrange);
                    ChartObjects.DrawText(s_ObjName, "\n|", x, h_y, vAlign, hAlign, Colors.White);

                    break;

            }
        }


        private bool Size(Candle candle)
        {
            if (candle.IsFallCandle())
            {
                if ((candle.Open - candle.Close) > (candle.High - candle.Low) * n)
                    return true;
            }
            else if (candle.IsRiseCandle())
            {
                if ((candle.Close - candle.Open) > (candle.High - candle.Low) * n)
                    return true;
            }

            return false;
        }

        private void Text_Info(int index, string Pattern_name)
        {
            if (Add_info == true)
            {

                #region Pattern

                ChartObjects.DrawText("PATTERN", "LAST PATTERN : " + Pattern_name, StaticPosition.TopLeft, Colors.White);

                #endregion Pattern

                #region MACD

                if (MACD_Info(index) == "UP")
                {
                    ChartObjects.DrawText("MACD", "\nMACD : ", StaticPosition.TopLeft, Colors.White);
                    ChartObjects.DrawText("ARROW MACD", "\n\t" + UpArrow, StaticPosition.TopLeft, Colors.DodgerBlue);

                }
                else if (MACD_Info(index) == "DOWN")
                {
                    ChartObjects.DrawText("MACD", "\nMACD : ", StaticPosition.TopLeft, Colors.White);
                    ChartObjects.DrawText("ARROW MACD", "\n\t" + DownArrow, StaticPosition.TopLeft, Colors.Crimson);
                }

                #endregion MACD

            }
        }

        private string MACD_Info(int index)
        {
            if (macd.Histogram[index] > 0)
            {
                return "UP";
            }

            if (macd.Histogram[index] < 0)
            {
                return "DOWN";
            }
            return "ZERO";
        }


        private bool Doji(Candle candle)
        {

            if (candle.IsFallCandle() & (candle.Close != candle.Low))
            {
                if ((candle.High - candle.Low) > 12 * (candle.Open - candle.Close))
                    return true;
            }
            if (candle.IsRiseCandle() & (candle.Close != candle.High))
            {
                if ((candle.High - candle.Low) > 12 * (candle.Close - candle.Open))
                    return true;
            }
            return false;
        }

        private bool Hammer(Candle candle)
        {
            if (candle.IsFallCandle() & (candle.Close == candle.Low))
            {
                if ((candle.Median() > candle.Open) & (candle.Median() > candle.Close))
                {
                    if ((candle.Median() - candle.Low) > 1.618 * (candle.Open - candle.Close))
                        return true;
                }
            }

            if (candle.IsRiseCandle() & (candle.Close == candle.High))
            {
                if ((candle.Median() < candle.Open) & (candle.Median() < candle.Close))
                {
                    if ((candle.High - candle.Median()) > 1.618 * (candle.Close - candle.Open))
                        return true;
                }
            }

            return false;
        }

        public override void Calculate(int index)
        {
            #region structs

            Candle candle = new Candle();

            #endregion structs

            #region variables

            int candle_index = 0;

            candle.High = MarketSeries.High.Last(candle_index);
            candle.Open = MarketSeries.Open.Last(candle_index);
            candle.Close = MarketSeries.Close.Last(candle_index);
            candle.Low = MarketSeries.Low.Last(candle_index);

            #endregion variables

            #region Patterns

            // Doji

            if (Doji(candle))
            {
                if (Show_Doji == true)
                {
                    Pattern_name = "Doji";
                    if (Name_Status == true)
                    {
                        DrawText(index, (int)PatternType.Doji);
                    }
                    else
                    {
                        DrawSymbols(index, (int)PatternType.Doji);
                    }
                }
            }

            //Hammer

            if (Hammer(candle))
            {
                if (Show_Hammer == true)
                {
                    Pattern_name = "Hammer";
                    if (Name_Status == true)
                    {
                        DrawText(index, (int)PatternType.Hammer);
                    }
                    else
                    {
                        DrawSymbols(index, (int)PatternType.Hammer);
                    }
                }
            }

            #endregion Patterns

            #region Text

            Text_Info(index, Pattern_name);

            #endregion Text
        }
    }
}
