using System;
using System.Collections.Generic;
using System.Text;

using System.Windows.Forms;
using System.Drawing;


namespace Chart
{

    public class SimpleCoordinator : ICoordPainter
    {

        private double[] sc = { 0.01, 0.02, 0.05, .1, .2, .5, 1.0, 2.0, 5.0, 10, 20, 50 };
        protected int[] n = new int[2];
        protected double[] scale = new double[2];
        protected int[] p = new int[2];
        protected ChartPerformer performer;
        public SimpleCoordinator(int nx, int ny, ChartPerformer performer)
        {
            this.performer = performer;
            n[0] = nx;
            n[1] = ny;
        }



        public static void ClearInsetsStatic(Control component, int[,] insets)
        {
            if (component == null)
            {
                return;
            }
            Color c = component.BackColor;
            Graphics g = Graphics.FromHwnd(component.Handle);
            Brush brush = new SolidBrush(c);
            g.FillRectangle(brush, 0, 0, insets[0, 0] - 1, component.Height);
            g.FillRectangle(brush, 0, component.Height - insets[1, 1] + 1, component.Width,
                insets[1, 1] - 1);
        }

        public virtual void ClearInsets(Control component, int[,] insets)
        {
            ClearInsetsStatic(component, insets);
        }


        public virtual void DrawCoord(Graphics g, double[,] dSize, int[] size)
        {
            calculateScale(dSize);
            DrawCoord(g, size, dSize, 0);
            DrawCoord(g, size, dSize, 1);
        }

        public virtual void DrawCoord(Graphics g, int[,] insets, double[,] dSize, int[] size)
        {
            calculateScale(dSize);
            Pen pen = new Pen(Color.Black);
            g.DrawRectangle(pen, insets[0, 0] - 1, insets[0, 1] - 1, size[0] + 2, size[1] + 2);
            drawTextX(g, insets, dSize, size);
            drawTextY(g, insets, dSize, size);
        }



        protected void calculateScale(double[,] dSize, int i)
        {
            double a = (dSize[1, i] - dSize[0, i]) / n[i];
            double log = Math.Log(a) / Math.Log(10.0);
            int lg = (int)Math.Ceiling(log);
            double c = 1;
            if (lg > 0)
            {
                for (int j = 0; j < lg; j++)
                {
                    c *= 10;
                }
            }
            else
            {
                for (int j = 0; j > lg; j--)
                {
                    c /= 10;
                }
            }
            double ss = c * sc[0];
            double acc = Math.Abs(ss - a);
            for (int j = 1; j < sc.Length; j++)
            {
                double sss = c * sc[j];
                double d = Math.Abs(sss - a);
                if (d < acc)
                {
                    ss = sss;
                    acc = d;
                }
            }
            scale[i] = ss;
        }

        protected void calculateScale(double[,] dSize)
        {
            calculateScale(dSize, 0);
            calculateScale(dSize, 1);
        }

        protected void DrawCoord(Graphics g, int[] size, double[,] dSize, int i)
        {
            double sc = scale[i];
            if (sc == 0)
            {
                return;
            }
            double a = dSize[0, i] / sc;
            long k = (long)a - 1;
            double c = k * sc;
            Pen pen = new Pen(Color.Black);
            while (c < dSize[1, i])
            {
                if (c > dSize[0, i])
                {
                    if (i == 0)
                    {
                        performer.Transform(c, 0.0, p);
                        g.DrawLine(pen, p[0], 0, p[0], size[1]);
                    }
                    else
                    {
                        performer.Transform(0, c, p);
                        g.DrawLine(pen, 0, p[1], size[0], p[1]);
                    }
                }
                c += sc;
            }
        }

        protected void drawTextX(Graphics g, int[,] insets, double[,] dSize, int[] size)
        {
            double sc = scale[0];
            if (sc == 0)
            {
                return;
            }
            int k = (int)(dSize[0, 0] / sc) - 1;
            double c = k * sc;
            Font font = new Font("Times", 13);
            Brush brush = new SolidBrush(Color.Black);
            int h = font.Height + insets[0, 1] + size[1];
            while (c < dSize[1, 0])
            {
                if (c > dSize[0, 0])
                {
                    performer.Transform(c, 0.0, p);
                    string s = transformString(c, sc);
                    int w = (int)g.MeasureString(s, font).Width;
                    g.DrawString(s, font, brush, p[0] + insets[0, 0] - w / 2, h);
                }
                c += sc;
            }
        }

        protected void drawTextY(Graphics g, int[,] insets, double[,] dSize, int[] size)
        {
            double sc = scale[1];
            if (sc == 0)
            {
                return;
            }
            long k = (long)(dSize[0, 1] / sc) - 1;
            double c = k * sc;
            Brush brush = new SolidBrush(Color.Black);
            Font font = new Font("Times", 13);
            while (c < dSize[1, 1])
            {
                if (c > dSize[0, 1])
                {
                    performer.Transform(0.0, c, p);
                    string s = transformString(c, sc);
                    int w = (int)g.MeasureString(s, font).Width;
                    g.DrawString(s, font, brush, insets[0, 0] - (int)(double)(1.2 * w), p[1] + insets[0, 1]);
                }
                c += sc;
            }
        }

        private string transformString(double d, double sc)
        {
            Double a = d;
            String s = a.ToString();
            while (true)
            {
                if (s.Length > 3 & s.IndexOf('E') < 0 & s.IndexOf('e') < 0)
                {
                    String s1 = s.Substring(0, s.Length - 1);
                    double d1 = Double.Parse(s1);
                    if (Math.Abs(d - d1) < 0.5 * sc)
                    {
                        s = s1;
                    }
                    else
                    {
                        break;
                    }
                }
                else
                {
                    break;
                }
            }
            return s;
        }
    }
}
