/* This file is part of AHD Subtitles Maker Professional
   A program can create and edit subtitles

   Copyright © Ala I Hadid 2009 - 2012

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.Resources;
using AHD.SM.ASMP;
using AHD.Forms;

namespace AHD.SM.Controls
{
    public partial class TimeLine : UserControl
    {
        public TimeLine()
        {
            InitializeComponent();
            timeLine_TicksPanel1.TimeChangeRequest += new EventHandler<TimeChangeArgs>(timeLine_TicksPanel1_TimeChangeRequest);

            gr_left = panel_left.CreateGraphics();
        }

        Graphics gr_left;
        ResourceManager resources = new ResourceManager("AHD.SM.Controls.LanguageResources.Resource",
         Assembly.GetExecutingAssembly());
        int TimeSpace = 1000;//the pixels of time space
        int ViewPortOffset = 0;//the pixel of viewport, view port is the panel_timeline width
        int MilliPixel = 10;//how milli each pixel presents
        double mediaDuration = 0;//this value will be used to calculate the timespace
        bool hasMedia = false;
        bool isPlaying = false;
        bool isZooming = false;
        #region Properties
        public Color MediaRectangleColor
        { get { return timeLine_Panel1.MediaRectangleColor; } set { timeLine_Panel1.MediaRectangleColor = value; } }
        public Color MediaHeaderRectangleColor
        { get { return timeLine_Panel1.MediaHeaderRectangleColor; } set { timeLine_Panel1.MediaHeaderRectangleColor = value; } }
        public Color SubtitleSelectedColor
        { get { return timeLine_Panel1.SubtitleSelectedColor; } set { timeLine_Panel1.SubtitleSelectedColor = value; } }
        public Color SubtitleRectangleColor
        { get { return timeLine_Panel1.SubtitleRectangleColor; } set { timeLine_Panel1.SubtitleRectangleColor = value; } }
        public Color SubtitleHeaderRectangleColor
        { get { return timeLine_Panel1.SubtitleHeaderRectangleColor; } set { timeLine_Panel1.SubtitleHeaderRectangleColor = value; } }
        public Color SubtitleStringColor
        { get { return timeLine_Panel1.SubtitleStringColor; } set { timeLine_Panel1.SubtitleStringColor = value; } }
        public Color TimeLineColor
        { get { return timeLine_Panel1.TimeLineColor; } set { timeLine_TicksPanel1.TimeLineColor = timeLine_Panel1.TimeLineColor = value; } }
        public Color ToolTipRectangleColor
        { get { return timeLine_Panel1.ToolTipRectangleColor; } set { timeLine_Panel1.ToolTipRectangleColor = value; } }
        public Color ToolTipTextColor
        { get { return timeLine_Panel1.ToolTipTextColor; } set { timeLine_TicksPanel1.ToolTipTextColor = timeLine_Panel1.ToolTipTextColor = value; } }
        public Color SelectionRectangleColor
        { get { return timeLine_Panel1.SelectionRectangleColor; } set { timeLine_Panel1.SelectionRectangleColor = value; } }
        public Color BackgroundColor
        { get { return timeLine_Panel1.BackgroundColor; } set { timeLine_TicksPanel1.ToolTipColor = timeLine_Panel1.BackgroundColor = value; } }
        public Color SplitersColor
        { get { return timeLine_Panel1.SplitersColor; } set { timeLine_Panel1.SplitersColor = value; } }
        public Color TickColor
        { get { return timeLine_TicksPanel1.TickColor; } set { timeLine_TicksPanel1.TickColor = value; } }
        public Color MarkColor
        { get { return timeLine_TicksPanel1.MarkColor; } set { timeLine_TicksPanel1.MarkColor = value; } }
        public Color TickPanelToolTipColor
        { get { return timeLine_TicksPanel1.ToolTipColor; } set { timeLine_TicksPanel1.ToolTipColor = value; } }
        public bool PreviewMode
        { get { return timeLine_Panel1.PreviewMode; } set { timeLine_Panel1.PreviewMode = timeLine_TicksPanel1.PreviewMode = value; } }
        public int MegnaticAccuracy
        { get { return timeLine_Panel1.MegnaticAccuracy; } set { timeLine_Panel1.MegnaticAccuracy = value; } }
        public int SmartToolAccuracy
        { get { return timeLine_Panel1.SmartToolAccuracy; } set { timeLine_Panel1.SmartToolAccuracy = value; } }
        #endregion
        #region Events
        /// <summary>
        /// Rised when the user request a time change
        /// </summary>
        public event EventHandler<TimeChangeArgs> TimeChangeRequest;
        /// <summary>
        /// Rised when the user selecte subtite(s)
        /// </summary>
        public event EventHandler SubtitlesSelected;
        public event EventHandler SubtitleDoubleClick;
        public event EventHandler SubtitlePropertiesChanged;
        /// <summary>
        /// Rised when the user asks to jump into time
        /// </summary>
        public event EventHandler JumpIntoTimeRequest;
        /// <summary>
        /// Rised up when the user asks to add mark
        /// </summary>
        public event EventHandler AddMarkRequest;
        /// <summary>
        /// Rised up when the user asks to remove mark
        /// </summary>
        public event EventHandler RemoveMarkRequest;
        /// <summary>
        /// Rised up when the user asks to jump into mark (selected mark)
        /// </summary>
        public event EventHandler JumpIntoMarkRequest;
        /// <summary>
        /// Rised up when the user asks to select a mark (at given time)
        /// </summary>
        public event EventHandler<MarkEditArgs> SelectMarkRequest;
        /// <summary>
        /// Rised up when the user finished edit a mark
        /// </summary>
        public event EventHandler<MarkEditArgs> MarkEdit;
        #endregion
        /// <summary>
        /// Re-assign the values of the hscroll bar
        /// </summary>
        void UpdateHScroll()
        {
            int max = TimeSpace + 100 - timeLine_Panel1.Width;
            if (max < 0)
                max = 1;
            hScrollBar1.Maximum = max;
        }
        void ScrollToCurrentTime()
        {
            ViewPortOffset = GetPixelOftime(timeLine_TicksPanel1.CurrentTime) - (timeLine_TicksPanel1.Width / 2);
            if (ViewPortOffset >= hScrollBar1.Maximum)
                ViewPortOffset = hScrollBar1.Maximum - 1;
            if (ViewPortOffset < 0)
                ViewPortOffset = 0;
            timeLine_Panel1.ViewPortOffset = timeLine_TicksPanel1.ViewPortOffset =
                hScrollBar1.Value = ViewPortOffset;
        }
        void UpdateViewport()
        {
            isZooming = true;
            int v = trackBar_zoom.Maximum - trackBar_zoom.Value;
            MilliPixel = v - (v % 5);
            if (MilliPixel < 5)
                MilliPixel = 5;
            TimeSpace = (int)((mediaDuration * 1000) / MilliPixel) + 100;
            timeLine_Panel1.TimeSpace = timeLine_TicksPanel1.TimeSpace = TimeSpace;
            timeLine_Panel1.MilliPixel = timeLine_TicksPanel1.MilliPixel = MilliPixel;

            UpdateHScroll();

            ScrollToCurrentTime();
            isZooming = false;
        }
        /// <summary>
        /// Calculate time using pixel
        /// </summary>
        /// <param name="x">The pixel to calculate time for, this pixel should be the real pixel of time space, not from view port</param>
        /// <returns>The time in Sec.Milli format</returns>
        double GetTime(int x)
        {
            int tas = TimeSpace * MilliPixel;
            int milli = (x * tas) / TimeSpace;
            return milli / 1000;
        }
        int GetPixelOftime(double time)
        {
            double tas = TimeSpace * MilliPixel;
            return (int)(((time * 1000) * TimeSpace) / tas);
        }

        public void UpdateTime(double time)
        {
            if (!isZooming & !timeLine_Panel1.isDrawing)
            {
                linkLabel1.Text = TimeFormatConvertor.To_TimeSpan_Milli(time);
                if (!timeLine_Panel1.isMovingTimeLine)
                {
                    timeLine_TicksPanel1.CurrentTime = time;
                    timeLine_Panel1.CurrentTime = time;
                }
                //auto scroll
                if ((GetPixelOftime(time) > ViewPortOffset + timeLine_TicksPanel1.Width) && isPlaying)
                {
                    ViewPortOffset = GetPixelOftime(time);
                    if (ViewPortOffset >= hScrollBar1.Maximum)
                        ViewPortOffset = hScrollBar1.Maximum - 1;
                    timeLine_Panel1.ViewPortOffset = timeLine_TicksPanel1.ViewPortOffset =
                        hScrollBar1.Value = ViewPortOffset;
                }

                timeLine_Panel1.Invalidate();
                timeLine_TicksPanel1.Invalidate();
            }
        }
        public SubtitlesTrack SubtitlesTrack
        {
            get { return timeLine_Panel1.SubtitlesTrack; }
            set
            {
                timeLine_Panel1.SubtitlesTrack = value;

                //in case we have no media :
                if (value != null && !hasMedia)
                {
                    if (value.Subtitles.Count > 0)
                    {
                        double newDuration = value.Subtitles[value.Subtitles.Count - 1].EndTime;
                        if (mediaDuration != newDuration && newDuration >= 10)
                        {
                            mediaDuration = newDuration;
                            trackBar_zoom.Maximum = (int)((mediaDuration * 1000) + 10000) / timeLine_Panel1.Width;
                            trackBar_zoom.Value = 5;
                            UpdateViewport();
                            hScrollBar1.Value = 0;
                            ViewPortOffset = 0;
                            //update scroll values
                            timeLine_TicksPanel1.ViewPortOffset = 0;
                            //timeLine_TicksPanel1.Invalidate();
                            timeLine_Panel1._mediaObjectDuration = 0;
                            timeLine_Panel1.ViewPortOffset = 0;
                            //timeLine_Panel1.Invalidate();
                        }
                    }
                }
                //timeLine_Panel1.Invalidate();
                SelectedSubtitles.Clear();
            }
        }
        public List<Subtitle> SelectedSubtitles
        {
            get { return timeLine_Panel1.SelectedSubtitles; }
            set
            {
                timeLine_Panel1.SelectedSubtitles = value;
                //timeLine_Panel1.Invalidate();
            }
        }
        public List<TimeMark> TimeMarks
        {
            get { return timeLine_TicksPanel1.timeMarks; }
            set
            {
                timeLine_TicksPanel1.timeMarks = value;
                //timeLine_TicksPanel1.Invalidate();
            }
        }
        public double MediaDuration
        {
            get { return timeLine_Panel1.MediaObjectDuration; }
            set
            {
                timeLine_Panel1.MediaObjectDuration = value;
                if (value != 0)
                { mediaDuration = value; hasMedia = true; }
                else
                { mediaDuration = 1000; hasMedia = false; }//1000 milli, no 0 accepted
                trackBar_zoom.Maximum = (int)((mediaDuration * 1000) + 10000) / timeLine_Panel1.Width;
                trackBar_zoom.Value = 5;
                trackBar_zoom_Scroll(this, new EventArgs());
                hScrollBar1.Value = 0;
                ViewPortOffset = 0;
                //update scroll values
                timeLine_TicksPanel1.ViewPortOffset = 0;
                //timeLine_TicksPanel1.Invalidate();

                timeLine_Panel1.ViewPortOffset = 0;
                //timeLine_Panel1.Invalidate();
            }
        }
        /// <summary>
        /// Set if media is playing, required for auto scroll feature
        /// </summary>
        public bool IsPlaying
        { set { isPlaying = value; } }

        private void panel_left_Paint(object sender, PaintEventArgs e)
        {
            //draw spliters
            e.Graphics.DrawLine(new Pen(new SolidBrush(Color.Gray)), 0, 0, this.Width, 0);
            e.Graphics.DrawLine(new Pen(new SolidBrush(Color.Gray)), 0, timeLine_Panel1.SpliterY, this.Width, timeLine_Panel1.SpliterY);
            e.Graphics.DrawLine(new Pen(new SolidBrush(Color.Gray)), 0, timeLine_Panel1.SpliterY * 2, this.Width, timeLine_Panel1.SpliterY * 2);
            //draw texts
            e.Graphics.DrawString(resources.GetString("Media"),
           new Font("Tahoma", 8, FontStyle.Bold),
           new SolidBrush(Color.Black), 30, ((timeLine_Panel1.SpliterY / 2) - 8));

            e.Graphics.DrawString(resources.GetString("SubtitlesTrack"),
   new Font("Tahoma", 8, FontStyle.Bold),
   new SolidBrush(Color.Black), 30, ((timeLine_Panel1.SpliterY / 2) - 8) + timeLine_Panel1.SpliterY);
        }
        private void hScrollBar1_Scroll(object sender, ScrollEventArgs e)
        {
            ViewPortOffset = hScrollBar1.Value;
            //update scroll values
            timeLine_Panel1.ViewPortOffset = ViewPortOffset;
            timeLine_TicksPanel1.ViewPortOffset = ViewPortOffset;
        }
        private void trackBar_zoom_Scroll(object sender, EventArgs e)
        {
            UpdateViewport();
        }
        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            timeLine_Panel1.editMode = TimeLineEditMode.Smart;
            timeLine_Panel1.smartEditMode = TimeLineSmartEditMode.None;
            toolStripButton_smart.Checked = true;
            toolStripButton_editStart.Checked = false;
            toolStripButton_move.Checked = false;
            toolStripButton_split.Checked = false;
            toolStripButton_editEnd.Checked = false;
            toolStripButton_selectTool.Checked = false;
        }
        private void toolStripButton_move_Click(object sender, EventArgs e)
        {
            timeLine_Panel1.editMode = TimeLineEditMode.Move;
            toolStripButton_smart.Checked = false;
            toolStripButton_editStart.Checked = false;
            toolStripButton_move.Checked = true;
            toolStripButton_split.Checked = false;
            toolStripButton_editEnd.Checked = false;
            toolStripButton_selectTool.Checked = false;
        }
        private void toolStripButton_edit_Click(object sender, EventArgs e)
        {
            timeLine_Panel1.editMode = TimeLineEditMode.EditStartTime;
            toolStripButton_smart.Checked = false;
            toolStripButton_editStart.Checked = true;
            toolStripButton_move.Checked = false;
            toolStripButton_split.Checked = false;
            toolStripButton_editEnd.Checked = false;
            toolStripButton_selectTool.Checked = false;
        }
        private void toolStripButton_split_Click(object sender, EventArgs e)
        {
            timeLine_Panel1.editMode = TimeLineEditMode.Split;
            toolStripButton_smart.Checked = false;
            toolStripButton_editStart.Checked = false;
            toolStripButton_move.Checked = false;
            toolStripButton_split.Checked = true;
            toolStripButton_editEnd.Checked = false;
            toolStripButton_selectTool.Checked = false;
        }
        private void toolStripButton_editEnd_Click(object sender, EventArgs e)
        {
            timeLine_Panel1.editMode = TimeLineEditMode.EditEndTime;
            toolStripButton_smart.Checked = false;
            toolStripButton_editStart.Checked = false;
            toolStripButton_move.Checked = false;
            toolStripButton_split.Checked = false;
            toolStripButton_editEnd.Checked = true;
            toolStripButton_selectTool.Checked = false;
        }
        private void toolStripButton_selectTool_Click(object sender, EventArgs e)
        {
            timeLine_Panel1.editMode = TimeLineEditMode.Select;
            toolStripButton_smart.Checked = false;
            toolStripButton_editStart.Checked = false;
            toolStripButton_move.Checked = false;
            toolStripButton_split.Checked = false;
            toolStripButton_editEnd.Checked = false;
            toolStripButton_selectTool.Checked = true;
        }
        private void timeLine_Panel1_SubtitlesSelected(object sender, EventArgs e)
        {
            if (SubtitlesSelected != null)
                SubtitlesSelected(sender, e);
        }
        private void timeLine_Panel1_SubtitleDoubleClick(object sender, EventArgs e)
        {
            if (SubtitleDoubleClick != null)
                SubtitleDoubleClick(sender, e);
        }
        void timeLine_TicksPanel1_TimeChangeRequest(object sender, TimeChangeArgs e)
        {
            if (TimeChangeRequest != null)
                TimeChangeRequest(sender, e);
            //timeLine_Panel1.Invalidate();
            //timeLine_TicksPanel1.Invalidate();
        }
        private void timeLine_Panel1_MovingTimeLine(object sender, EventArgs e)
        {
            timeLine_TicksPanel1.CurrentTime = timeLine_Panel1.CurrentTime;
        }
        private void timeLine_Panel1_SubtitlePropertiesChanged(object sender, EventArgs e)
        {
            if (SubtitlePropertiesChanged != null)
                SubtitlePropertiesChanged(sender, e);
        }
        //zoom in/out
        private void toolStripButton1_Click_1(object sender, EventArgs e)
        {
            try
            {
                trackBar_zoom.Value += 5;
                UpdateViewport();
            }
            catch { }
        }
        private void toolStripButton2_Click(object sender, EventArgs e)
        {
            try
            {
                trackBar_zoom.Value -= 5;
                UpdateViewport();
            }
            catch { }
        }
        private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            if (JumpIntoTimeRequest != null)
                JumpIntoTimeRequest(sender, new EventArgs());
        }
        //set current as track start, shift
        private void toolStripButton1_Click_2(object sender, EventArgs e)
        {
            if (this.SubtitlesTrack == null)
                return;
            if (this.SubtitlesTrack.Subtitles.Count == 0)
                return;
            double subsstart = this.SubtitlesTrack.Subtitles[0].StartTime;
            double Shift = timeLine_Panel1.CurrentTime - subsstart;
            if (this.SubtitlesTrack.Subtitles[this.SubtitlesTrack.Subtitles.Count - 1].EndTime + Shift > mediaDuration)
            {
                if ((MessageDialog.ShowMessage(this, resources.GetString("Message_TheTimeYouSetWillMakeTheSubtitlesTrackEndAtAPositionMoreThanTheMediaDuration"),
                   resources.GetString("MessageCaption_Warning"), (MessageDialogButtons.Ok | MessageDialogButtons.Checked), MessageDialogIcon.Warning, false,
                    resources.GetString("Button_Ok"), "", "", resources.GetString("Button_Ignore")) & MessageDialogResult.Checked) != MessageDialogResult.Checked)
                {
                    return;
                }
            }
            foreach (Subtitle sub in this.SubtitlesTrack.Subtitles)
            {
                sub.StartTime += Shift;
                sub.EndTime += Shift;
            }

            if (SubtitlePropertiesChanged != null)
                SubtitlePropertiesChanged(this, new EventArgs());
        }
        //set current as track end, shift
        private void toolStripButton2_Click_1(object sender, EventArgs e)
        {
            if (this.SubtitlesTrack == null)
                return;
            if (this.SubtitlesTrack.Subtitles.Count == 0)
                return;
            double subsend = this.SubtitlesTrack.Subtitles[0].EndTime;
            double Shift = timeLine_Panel1.CurrentTime - subsend;
            if (this.SubtitlesTrack.Subtitles[0].StartTime + Shift < 0)
            {
                MessageDialog.ShowMessage(this, resources.GetString("Message_TheTimeYouSetWillMakeTheSubtitlesTrackStartAtAPositionLessThan0"),
                        resources.GetString("MessageCaption_Error"), MessageDialogButtons.Ok, MessageDialogIcon.Error);
                return;
            }
            foreach (Subtitle sub in this.SubtitlesTrack.Subtitles)
            {
                sub.StartTime += Shift;
                sub.EndTime += Shift;
            }

            if (SubtitlePropertiesChanged != null)
                SubtitlePropertiesChanged(this, new EventArgs());
        }
        //Set start with compress
        private void toolStripButton5_Click(object sender, EventArgs e)
        {
            if (this.SubtitlesTrack == null)
                return;
            if (this.SubtitlesTrack.Subtitles.Count == 0)
                return;
            double currenttime = timeLine_Panel1.CurrentTime;
            double OrgenalStart = this.SubtitlesTrack.Subtitles[0].StartTime;
            double OrgenalMax = this.SubtitlesTrack.Subtitles[this.SubtitlesTrack.Subtitles.Count - 1].EndTime - this.SubtitlesTrack.Subtitles[0].StartTime;
            double NewMax = this.SubtitlesTrack.Subtitles[this.SubtitlesTrack.Subtitles.Count - 1].EndTime - currenttime;

            if (NewMax <= 0)
            {
                MessageDialog.ShowMessage(this, resources.GetString("Message_TheNewDurationWillBeLessOrEqual0"),
                resources.GetString("MessageCaption_Error"), MessageDialogButtons.Ok, MessageDialogIcon.Error);
                return;
            }

            foreach (Subtitle sub in this.SubtitlesTrack.Subtitles)
            {
                double OldStart = sub.StartTime - OrgenalStart;//- OrgenalStart to return to 0
                double OldEnd = sub.EndTime - OrgenalStart;

                double NewStart = ((OldStart * NewMax) / OrgenalMax);
                double NewEnd = ((OldEnd * NewMax) / OrgenalMax);
                sub.StartTime = NewStart + currenttime;
                sub.EndTime = NewEnd + currenttime;
            }
            if (SubtitlePropertiesChanged != null)
                SubtitlePropertiesChanged(this, new EventArgs());
        }
        //Set end with compress
        private void toolStripButton6_Click(object sender, EventArgs e)
        {
            if (this.SubtitlesTrack == null)
                return;
            if (this.SubtitlesTrack.Subtitles.Count == 0)
                return;
            double currenttime = timeLine_Panel1.CurrentTime;
            double OrgenalStart = this.SubtitlesTrack.Subtitles[0].StartTime;
            double subsend = this.SubtitlesTrack.Subtitles[this.SubtitlesTrack.Subtitles.Count - 1].EndTime;

            double OrgenalMax = this.SubtitlesTrack.Subtitles[this.SubtitlesTrack.Subtitles.Count - 1].EndTime - OrgenalStart;
            double NewMax = currenttime - OrgenalStart;
            if (NewMax <= 0)
            {
                MessageDialog.ShowMessage(this, resources.GetString("Message_TheNewDurationWillBeLessOrEqual0"),
                resources.GetString("MessageCaption_Error"), MessageDialogButtons.Ok, MessageDialogIcon.Error);
                return;
            }
            foreach (Subtitle sub in this.SubtitlesTrack.Subtitles)
            {
                double OldStart = sub.StartTime - OrgenalStart;//- OrgenalStart to return to 0
                double OldEnd = sub.EndTime - OrgenalStart;

                double NewStart = ((OldStart * NewMax) / OrgenalMax);
                double NewEnd = ((OldEnd * NewMax) / OrgenalMax);

                sub.StartTime = NewStart + OrgenalStart;
                sub.EndTime = NewEnd + OrgenalStart;
            }
            if (SubtitlePropertiesChanged != null)
                SubtitlePropertiesChanged(this, new EventArgs());
        }
        //marks
        private void toolStripButton7_Click(object sender, EventArgs e)
        {
            if (AddMarkRequest != null)
                AddMarkRequest(sender, e);
        }
        private void toolStripButton8_Click(object sender, EventArgs e)
        {
            if (RemoveMarkRequest != null)
                RemoveMarkRequest(sender, e);
        }
        private void toolStripButton9_Click(object sender, EventArgs e)
        {
            if (JumpIntoMarkRequest != null)
                JumpIntoMarkRequest(sender, e);
        }
        private void timeLine_TicksPanel1_MarkEdit(object sender, MarkEditArgs e)
        {
            if (MarkEdit != null)
                MarkEdit(sender, e);
        }
        private void timeLine_TicksPanel1_SelectMarkRequest(object sender, MarkEditArgs e)
        {
            if (SelectMarkRequest != null)
                SelectMarkRequest(sender, e);
        }
        //scroll to current time
        private void toolStripButton10_Click(object sender, EventArgs e)
        {
            ScrollToCurrentTime();
        }
    }
}