using System;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;

namespace CFBandwidth
{
    public partial class Graph : Form
    {
        private Bitmap bmp;
        private Graphics g;
        private PictureBox display;

        private Linear_Regression ln;
        BandwidthMeter bm;

        int MTU;
        int step;
        int MIN;
        int delayMax = 50;

        int x0;                                         // x coordinate of 0,0 point
        int y0;                      // y coordinate of 0,0 point
        int delayAxisLength;
        int packetSizeAxisEnd;

        public Graph(BandwidthMeter _bm, Linear_Regression _ln)
        {
            x0 = 20;                                         // x coordinate of 0,0 point
            y0 = 30 + this.Height / 2;                       // y coordinate of 0,0 point
            delayAxisLength = this.Height / 2 - 10;
            packetSizeAxisEnd = this.Width - 10;

            bm = _bm;
            ln = _ln;
            MTU = bm.MTU;
            step = bm.step;
            MIN = bm.MIN;
            delayMax = Convert.ToInt32(bm.results.Max() * 2 / 1000);

            InitializeComponent();
            drawAxis();
            drawPoints();
            drawRegresion();

        }

        public void drawAxis()
        {

            bmp = new Bitmap(this.Width, this.Height);
            g = Graphics.FromImage(bmp);

            g.FillRectangle(new SolidBrush(Color.White), new Rectangle(0, 0, this.Width, this.Height));
            g.DrawLine(new Pen(Color.Black, 2), x0, y0, x0, y0 - delayAxisLength);
            g.DrawLine(new Pen(Color.Black, 2), x0, y0, packetSizeAxisEnd, y0);


            g.DrawString("Delay [ms]", new Font("Calibri", 9, FontStyle.Regular), new SolidBrush(Color.Black), 4, y0 - delayAxisLength - 20);
            g.DrawString("Data Size [byte]", new Font("Calibri", 9, FontStyle.Regular), new SolidBrush(Color.Black), (packetSizeAxisEnd / 2) - 40, y0 + 25);

            //drawing size scale
            #region //drawing size scale
            for (int i = MIN; i < MTU; i = i + step)
            {
                g.DrawLine(new Pen(Color.Black, 1), x0 + ((packetSizeAxisEnd - x0) * i / MTU), y0 - 3, x0 + ((packetSizeAxisEnd - x0) * i / MTU), y0 + 3);
                g.DrawString(i.ToString(), new Font("Calibri", 6, FontStyle.Regular), new SolidBrush(Color.Green), x0 + ((packetSizeAxisEnd - x0) * i / MTU) - 5, y0 + 10);
            }
            #endregion
            //drawing delay scale
            #region drawing delay scale
            g.DrawString(((Convert.ToInt32(delayMax))).ToString(), new Font("Calibri", 6, FontStyle.Regular), new SolidBrush(Color.Green), x0 - 16, y0 - delayAxisLength-3);
            g.DrawString(((Convert.ToInt32(3 * delayMax / 4))).ToString(), new Font("Calibri", 6, FontStyle.Regular), new SolidBrush(Color.Green), x0 - 16, y0 - (3 * delayAxisLength / 4) - 3);
            g.DrawString(((Convert.ToInt32(delayMax / 2))).ToString(), new Font("Calibri", 6, FontStyle.Regular), new SolidBrush(Color.Green), x0 - 16, y0 - (delayAxisLength / 2) - 3);
            g.DrawString(((Convert.ToInt32(delayMax / 4))).ToString(), new Font("Calibri", 6, FontStyle.Regular), new SolidBrush(Color.Green), x0 - 16, y0 - (delayAxisLength / 4) - 3);
            g.DrawString(((Convert.ToInt32(0))).ToString(), new Font("Calibri", 6, FontStyle.Regular), new SolidBrush(Color.Green), x0 - 16, y0 - 3);
            
            g.DrawLine(new Pen(Color.Black, 1), x0 - 3, y0, x0 + 2, y0);
            g.DrawLine(new Pen(Color.Black, 1), x0 - 3, y0 - delayAxisLength, x0 + 2, y0 - delayAxisLength);
            g.DrawLine(new Pen(Color.Black, 1), x0 - 3, y0 - (delayAxisLength / 2), x0 + 2, y0 - (delayAxisLength / 2));
            g.DrawLine(new Pen(Color.Black, 1), x0 - 3, y0 - (3 * delayAxisLength / 4), x0 + 2, y0 - (3 * delayAxisLength / 4));
            g.DrawLine(new Pen(Color.Black, 1), x0 - 3, y0 - (delayAxisLength / 4), x0 + 2, y0 - (delayAxisLength / 4));
            #endregion
            display = new PictureBox();
            display.Width = this.Width;
            display.Height = this.Height;
            this.Controls.Add(display);
            display.Image = bmp;
        }


        public void drawPointRed(double size, double delay)
        {
            delay = delay / 1000;
            g.DrawEllipse(new Pen(Color.Red, 2), Convert.ToInt32(x0 + ((packetSizeAxisEnd - x0) * size / MTU)), Convert.ToInt32(y0 - delayAxisLength * (delay / delayMax)), 1, 1);
        }

        public void drawPointBlue(double size, double delay)
        {
            delay = delay / 1000;
            g.DrawEllipse(new Pen(Color.Blue, 2), Convert.ToInt32(x0 + ((packetSizeAxisEnd - x0) * size / MTU)), Convert.ToInt32(y0 - delayAxisLength * (delay / delayMax)), 1, 1);
        }

        public void drawPoints()
        {
            int i = 0;
            int s = MIN;
            foreach (List<double> list in bm.ListRtt)
            {
                i++;
                Debug.WriteLine(i.ToString());
                foreach (double rtt in list)
                {
                    Debug.WriteLine(" " + (rtt / 1000).ToString() + " " + s.ToString());
                    drawPointBlue(s, rtt);
                }

                drawPointRed(s, list.Min());

                s = s + step;
            }
        }

        public void drawRegresion()
        {
            double a = ln.getA();
            double b = ln.getB();

            int x1 = x0;
            int y1 = Convert.ToInt32(y0 - (delayAxisLength * b / delayMax));

            int x2 = packetSizeAxisEnd;
            int y2 = Convert.ToInt32(y0 - (delayAxisLength * (a * MTU + b) / delayMax)); ;

            g.DrawString("Regression Line: y =" + Math.Round(a, 4).ToString() + "*x + " + Math.Round(b, 4).ToString(), new Font("Calibri", 9, FontStyle.Regular), new SolidBrush(Color.Black), 10, 250);
            g.DrawString("Bandwidth: " + (2 * Math.Round(ln.getBandwidth(), 2)).ToString() + " Mb/s", new Font("Calibri", 9, FontStyle.Regular), new SolidBrush(Color.Black), 10, 225);
            g.DrawLine(new Pen(Color.Black, 1), x1, y1, x2, y2);
        }
    }
}