using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using WMPLib;

/*
 * Welcome to DCS-VECANO (Version Change Notifier)!!!
 * 
 * To enable the trick:
 * 1. Swap comments for websiteToCheck variable.
 * 2. Swap comments on the three h2_ variables.
 * 3. Uncomment the "else if (downloadString1 != downloadString2)" section.
 * 4. Run program and Listen 4/For Updates. You should see lots of jibberish.
 * 5. Change the site HTML.
 * 6. That should do it.
 * 7. If you want to trick it into geting a DCS Update, change:
 * "if (LateststableversionString != LateststableversionString_2)"
 * to "if (LateststableversionString == LateststableversionString_2)"
 * 
 * TODO: Document and comment everything so I know what's going on.
 * TODO: Make the variables less global-y (maybe)
 * TODO: Make this less of a CPU hog. Much Less. Plz.
 * 
 * Version Log:
 * v02
 * +Made the app ~96.667% more CPU efficient. Bye bye While loops!
 * +Added tons of programming comments
 * +Changed Listen 4 Updates to "Listen For Updates"
 * v01
 * +Release
 */

namespace DCS_VersionUpdateNotifier
{
    public partial class Form1 : Form
    {
        //DCS Version Change Notifier
        //Global Variables
        string userSelectedNotificationSound = "";//this preloads the string so that an error
        //isnt made if the user never chose a sound
        string userGmailAddress;//user inputs their gmail address
        string userGmailPassword;//users gmail password
        int userSetUpdateInterval;//this is the interval at which this app checks the site, waits, and then checks again
        bool hasUpdateHappened;//if the site HTML changed, this flags true
        bool didUserSelectMusic;//if a user selects music, this flags true
        bool doesUserHaveAddressAndPassword;//if this is grey, i didnt use it
        bool hasUserEnabledIntervalShortcut;//this is a personal debug cheat. Click my name in the
        //program before doing anything else to shorten the check interval

        string websiteToCheck = "http://updates.digitalcombatsimulator.com/";//this site is updated when the 
        //DCS servers are updated
        //string websiteToCheck = "https://anotepad.com/notes/chp32te";//this is the site used to test the HTML changes
        //string websiteToCheck = "https://www.digitalcombatsimulator.com/en/shop/modules/";//dcs modules page. monitor for new aircraft
        //string websiteToCheck = "https://www.digitalcombatsimulator.com/en/news/";//dcs new page. monitor for news

        string downloadString1;//this contains the HTML of the first website get
        string downloadString2;//this contains the HTML of the second website get

        //the index of <h2> in the HTML, which tells is that its the sart of the version
        //</h2> tells us its the end.
        //to know the above, I just had to look in the HTML and pick those defining features
        int indexStartOfStableVersionLine;
        int indexEndOfStableVersionLine;
        string LateststableversionString;//this string, using math, contains the version number
        int indexStartOfBetaVersionLine;
        int indexEndOfBetaVersionLine;
        string LatestBetaversionString;//this string, using math, contains the version number

        //this stuff below is the same as above, but for the second HTML get
        int indexStartOfStableVersionLine_2;
        int indexEndOfStableVersionLine_2;
        string LateststableversionString_2;
        int indexStartOfBetaVersionLine_2;
        int indexEndOfBetaVersionLine_2;
        string LatestBetaversionString_2;

        //I put these in to debug for other sites. can be used to change what to look for
        string h2_endOfVersionNumber = "</h2>";
        string h2_beginingOfStable = "<h2>Latest stable version";
        string h2_beginingOfBeta = "<h2>Current openbeta";

        bool isFetchingDownload1 = true;

        //string h2_endOfVersionNumber = "</head>";
        //string h2_beginingOfStable = "<head>";
        //string h2_beginingOfBeta = "<head>";
    

        public Form1()
        {
            InitializeComponent();
            Timer1.Interval = 1000 * 60 * 5;//(milliseconds)(seconds)(minutes total)
        }//typical Winform stuff. Initializes the draw stuff, i think

        private void Button1_Click(object sender, EventArgs e)
        {
            //when this button is clicked, all the variables will be retrieved and then 
            //the method that will be doing all of the legwork will be called
          
            userGmailAddress = textBox_gmailAddress.Text;
            userGmailPassword = textBox_gmailPassword.Text;
            //I took the clears out because it if you started the checker after a change was detected,
            //you wouldnt get an email because the boxes would have had empty strings
            //textBox_gmailAddress.Clear(); 
            //textBox_gmailPassword.Clear();
            this.Size = new Size(350, 130);//when the button is clicked, the screen resizes
            //this does 2 things, 1) Lets the user know that something happened
            //2) hides the unnecessary stuff
            userSetUpdateInterval = 60 * 5;//seconds * minutes
            userSetUpdateInterval *= 1000;//convert to seconds because original number is in millisonds
            intervalShortcut();//this method is made to reduce the wait time. for debuging
            hasUpdateHappened = false;
            label_emailSent.Visible = false;
            label_topArrow.Text = "---";
            label_bottomArrow.Text = "---";
            label_updateStatus.Text = "Wait for first update check...";
            getDcsVersions1();//populates both strings so they can have something to be compared to
            getDcsVersions2();
            Timer1.Enabled = true;
            //listen4Updates();
        }

        private void Button_selectNotification_Click(object sender, EventArgs e)
        {
            //user can only chose mp3 or wav because thats what i have it programed for
            //and they are the most popular file types
            openFileDialog1.Title = "Choose mp3 or wav for DCS-VECANO";
            openFileDialog1.ShowDialog();

            //openFileDialog1.InitialDirectory = "c:\\";
            //openFileDialog1.Filter = "Music Files (*.mp3;*.wav)";//i tried limiting the options to mp3 or wav, but
            //i couldnt get it to work.
            userSelectedNotificationSound = openFileDialog1.FileName;//this variable becomes what the user chose

            if (userSelectedNotificationSound.EndsWith(".wav") || userSelectedNotificationSound.EndsWith(".mp3"))
            { //keep going
                didUserSelectMusic = true;
            }
            else
            {
                MessageBox.Show("You didn't chose a .wav or .mp3 file. Try again, or don't.");
                userSelectedNotificationSound = "";//resetting the string to prevent errors
                didUserSelectMusic = false;
            }
        }

        private void Button_visitDcsSite_Click(object sender, EventArgs e)
        {//sends the user to the DCS update site. might replace with something more useful
            System.Diagnostics.Process.Start("http://updates.digitalcombatsimulator.com/");
        }

        private void Timer1_Tick_1(object sender, EventArgs e)
        {
            if (isFetchingDownload1 == true)//swaps which download variable gets loaded every tick
            {
                getDcsVersions1();
                isFetchingDownload1 = false;
                //label_timeOfLastUpdateCheck.Text = DateTime.Now.ToString();
                listen4Updates();
            }
            else
            {
                getDcsVersions2();
                isFetchingDownload1 = true;
                //label_timeOfLastUpdateCheck.Text = DateTime.Now.ToString();
                listen4Updates();
            }
        }
      
        public void listen4Updates()
        {
            if (hasUpdateHappened == false)//while there hasnt been an update...
            {
                //getDcsVersions1();//this downloads and parses the HTML info
                //wait(userSetUpdateInterval);//pause function
                //Thread.Sleep(userSetUpdateInterval);//another pause function, but it does not lest the user interact
                //with the window for some reason
                //getDcsVersions2();//this downloads and parses the HTML info the second time
                label_timeOfLastUpdateCheck.Text = "Last Checked: " + DateTime.Now.ToString();
                //label_timeOfLastUpdateCheck.Text = DateTime.Now.ToString("h:mm:ss tt");//lets the user know that 
                //the updates were checked
                //update the text with the version numbers that were retrieved
                label_DcsStableVersionOld.Text = LateststableversionString;
                label_DcsStableVersionNew.Text = LateststableversionString_2;
                label_DcsBetaVersionOld.Text = LatestBetaversionString;
                label_DcsBetaVersionNew.Text = LatestBetaversionString_2;
             
                if (LateststableversionString != LateststableversionString_2)//if stable is different, then it was updated
                {
                    hasUpdateHappened = true;
                    Timer1.Enabled = false;
                    label_updateStatus.Text = "DCS Stable Has Been Updated!";
                    //label_DcsStableVersionOld.Text = LateststableversionString;//i dont think i need this
                    label_topArrow.Text = "--->";
                    //label_DcsStableVersionNew.Text = LateststableversionString_2;//i dont think i need this
                    //label_DcsStableVersionNew.Text = LatestBetaversionString_2;//faked for demo
                    sendEmailToUser();
                    playUserSelectedSound();
                }
                else if (LatestBetaversionString != LatestBetaversionString_2)//if beta is different, then it was updated
                {
                    hasUpdateHappened = true;
                    Timer1.Enabled = false;
                    label_updateStatus.Text = "DCS Beta Has Been Updated!";
                    //label_DcsBetaVersionOld.Text = LatestBetaversionString;//i dont think i need this
                    label_bottomArrow.Text = "--->";
                    //label_DcsBetaVersionNew.Text = LatestBetaversionString_2;//i dont think i need this
                    sendEmailToUser();
                    playUserSelectedSound();
                }
                 //this is for random site testing
                /*else if (downloadString1 != downloadString2)
                {
                    hasUpdateHappened = true;
                    label_updateStatus.Text = "Site has been changed";
                    sendEmailToUser();
                    playUserSelectedSound();
                }*/
                
                else //nothing updated
                {
                    hasUpdateHappened = false;
                    label_updateStatus.Text = "DCS Update in Two Weeks";//can replace with something more user/ED friendly
                }
            }
        }

        public void getDcsVersions1()
        {
            WebClient client1 = new WebClient();
            downloadString1 = client1.DownloadString(websiteToCheck);//downloads the HTML from the site

            indexStartOfStableVersionLine = downloadString1.IndexOf(h2_beginingOfStable);//looks for the index of this
            indexEndOfStableVersionLine = downloadString1.IndexOf(h2_endOfVersionNumber, indexStartOfStableVersionLine);//start searching after h2_beginingOfStable
            //get the contents of what is inbetween the 2 above indexes
            //taking away the first 29 characters, had to count by hand
            LateststableversionString = downloadString1.Substring(indexStartOfStableVersionLine + 29 , indexEndOfStableVersionLine - indexStartOfStableVersionLine - 29); 

            indexStartOfBetaVersionLine = downloadString1.IndexOf(h2_beginingOfBeta);//looks for the index of this
            indexEndOfBetaVersionLine = downloadString1.IndexOf(h2_endOfVersionNumber, indexStartOfBetaVersionLine);//start searching after h2_beginingOfBeta
            //taking away the first 24 characters, had to count by hand
            LatestBetaversionString = downloadString1.Substring(indexStartOfBetaVersionLine + 24, indexEndOfBetaVersionLine - indexStartOfBetaVersionLine - 24);
        }

        public void getDcsVersions2() //similar to getDcsVersions1()
        {
            WebClient client2 = new WebClient();
            downloadString2 = client2.DownloadString(websiteToCheck);

            indexStartOfStableVersionLine_2 = downloadString2.IndexOf(h2_beginingOfStable);//looks for the index of this
            indexEndOfStableVersionLine_2 = downloadString2.IndexOf(h2_endOfVersionNumber, indexStartOfStableVersionLine_2);//start searching after <h2>
            LateststableversionString_2 = downloadString2.Substring(indexStartOfStableVersionLine_2 + 29, indexEndOfStableVersionLine_2 - indexStartOfStableVersionLine_2 - 29);

            indexStartOfBetaVersionLine_2 = downloadString2.IndexOf(h2_beginingOfBeta);//looks for the index of this
            indexEndOfBetaVersionLine_2 = downloadString2.IndexOf(h2_endOfVersionNumber, indexStartOfBetaVersionLine_2);//start searching after <h2>
            LatestBetaversionString_2 = downloadString2.Substring(indexStartOfBetaVersionLine_2 + 24, indexEndOfBetaVersionLine_2 - indexStartOfBetaVersionLine_2 - 24);
        }
       
        public void playUserSelectedSound()
        {
            if (didUserSelectMusic == true)
            {
                if (userSelectedNotificationSound.EndsWith(".wav"))//need to know so correct player can be used
                {
                    System.Media.SoundPlayer player = new System.Media.SoundPlayer(@userSelectedNotificationSound);
                    player.Play();
                }
                else if (userSelectedNotificationSound.EndsWith(".mp3"))//need to know so correct player can be used
                {
                    WindowsMediaPlayer myplayer = new WindowsMediaPlayer();//had to include a reference things for this
                    myplayer.URL = @userSelectedNotificationSound;
                    myplayer.controls.play();
                }
            }
        }
        /*
        public void wait(int milliseconds)//used this to fix the problem that the user couldnt interact with
            //the app when the thread was paused. I dont know, but this may be causeing the high CPU costs
            //explore "winform timer" or "C# timer"
        {//https://stackoverflow.com/questions/10458118/wait-one-second-in-running-program
            System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer();
            if (milliseconds == 0 || milliseconds < 0) return;
            //Console.WriteLine("start wait timer");
            timer1.Interval = milliseconds;
            timer1.Enabled = true;
            timer1.Start();
            timer1.Tick += (s, e) =>
            {
                timer1.Enabled = false;
                timer1.Stop();
                //Console.WriteLine("stop wait timer");
            };
            while (timer1.Enabled)
            {
                Application.DoEvents();
            }
        }
        *///wait method
        public void sendEmailToUser()
        {
            if (userGmailAddress == "") return;//leave this method if this field was blank
            if (userGmailPassword == "") return;//leave this method if this field was blank
            MailMessage mail = new MailMessage();
            SmtpClient SmtpServer = new SmtpClient("smtp.gmail.com");//maybe expant to outlook or other emails in future

            mail.From = new MailAddress("DCS-VECANO@gmail.com");//this does not work as expected
            try//i have no idea what i am doing here, but i think it actually worked. it is an attempt to catch errors
            {
                mail.Bcc.Add(userGmailAddress);
            }
            catch (FormatException ex)
            {
                label_emailSent.Text = "Email Not Sent";
                label_emailSent.Visible = true;
                return;
            }

            mail.Subject = "DCS Version Has Changed!";
            //print out the old and new versions
            string emailMessage = "Stable: " + LateststableversionString + " --> " + LateststableversionString_2 + "\n"
                + "Beta: " + LatestBetaversionString + " --> " + LatestBetaversionString_2 + "\n"
                + "Sent via DCS-VECANO by Bailey.";
            mail.Body = emailMessage;

            SmtpServer.Port = 587;
            SmtpServer.Credentials = new System.Net.NetworkCredential(userGmailAddress, userGmailPassword);//this info was recieved from the user in the beginning
            SmtpServer.EnableSsl = true;

            try //code from: https://docs.microsoft.com/en-us/dotnet/api/system.net.mail.smtpexception?view=netframework-4.8
            {
                SmtpServer.Send(mail);
            }
            catch (SmtpFailedRecipientsException ex)
            {
                //MessageBox.Show("Couldn't send Email. Sry.");
                label_emailSent.Text = "Email Not Sent";//lets the user know that it wasnt sent. maybe include more verbose
                //reasons in the future
                label_emailSent.Visible = true;
                return;
            }
            catch (Exception ex)
            {
                //MessageBox.Show("Couldn't send Email. Sry.");
                label_emailSent.Text = "Email Not Sent";
                label_emailSent.Visible = true;
                return;
            }
            label_emailSent.Text = "Email Sent";
            label_emailSent.Visible = true;
        }

        private void Label11_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Welcome to DCS-VECANO (Version Change Notifier)!!!\r\n\r\n" +
                "This project is for the DCS community. It will notify you when the DCS update site's HTML has " +
                "changed. This is usually a good way to know that a version number changed. My personal  strategy is to turn it on within a few " +
                "hours before a known update. Or run it on a spare computer before you go to work or to sleep ;) \r\n\r\n " +
                "How to use this app:\r\n" +
                "1. Open this program.\r\n" +
                "2. If you want a .wav or .mp3 sound to play when a " +
                "change has been detected, select it using the \"Select Notification Sound\" button. \r\n" +
                "3. If you would like to be notified via email when a changed has been detected, " +
                "put in your email address and password. No information is saved and none of " +
                "your info is sent anywhere. Those with two-factor authentication on their " +
                "Gmail Account may have to take some extra steps to use the Gmail notification " +
                "feature. If you have two-factor authentication on your Gmail Account, follow these " +
                "instructions: \r\n" +
                "   -a. Sign into your Gmail account at https://mail.google.com, " +
                "then go to Settings > Accounts and Import > Other Google Account settings. (You can make Gmail accounts for free if you want one.)\r\n" +
                "   -b. Under Security, scroll down and enable access for less secure apps. " +
                "This is essential for IMAP, POP and SMTP connections. The Gmail notification is " +
                "100% optional.  \r\n" +
                "5. When you are ready, click the \"Listen for Updates\" button. The app will " +
                "evaluate the HTML code of the DCS Update webpage on an timer.  \r\n\r\n" +
                "This application was created to monitor the release of DCS World updates. It has " +
                "been redesigned from a command line interface to what you see here. Thank you Santi " +
                "from the DCS Discord for the motivation for this project and BIGNEWY of the DCS Discord for the idea. " +
                "If you have any questions, comments, improvements, suggestions, concerns, just want to say Hi, etc., " +
                "please feel free to contact me on Discord: Bailey#6230.\r\n\r\n ~Bailey 01DEC2019");
        }//about page

        public void intervalShortcut()
        {
            if (hasUserEnabledIntervalShortcut == true)//if my name was clicked...
            {
                //currently set to 2 seconds.
                Timer1.Interval = 1000 * 2;
                //userSetUpdateInterval = 2;//tempoary placeholder.
                //userSetUpdateInterval *= 1000;
            }
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            Dispose();
            Environment.Exit(0);//completely shuts the app down. There was a bug where
            //if it was Listening 4 Updates, it wouldn't close out all the way.
        }

        public new void Dispose()//https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose?redirectedfrom=MSDN
        {
            // Dispose of unmanaged resources.
            Dispose(true);
            // Suppress finalization.
            GC.SuppressFinalize(this);
        }//idk, but it works!


        private void Label1_Click(object sender, EventArgs e)
        {

        }//empty
        private void Label5_Click(object sender, EventArgs e)
        {

        }//empty
        private void Label8_Click(object sender, EventArgs e)
        {

        }//empty
        private void TextBox_timeOfLastUpdateCheck_TextChanged(object sender, EventArgs e)
        {

        }//empty
        private void OpenFileDialog1_FileOk(object sender, CancelEventArgs e)
        {

        }//empty
        private void Label10_Click(object sender, EventArgs e)
        {
            hasUserEnabledIntervalShortcut = true;
        }//empty
        private void Form1_Load(object sender, EventArgs e)
        {

        }//empty
        private void TextBox_gmailAddress_TextChanged(object sender, EventArgs e)
        {


        }//empty
        private void TextBox_gmailPassword_TextChanged(object sender, EventArgs e)
        {


        }//empty

        private void Label_timeOfLastUpdateCheck_Click(object sender, EventArgs e)
        {

        }

        private void Label_emailSent_Click(object sender, EventArgs e)
        {

        }

        private void Label_updateStatus_Click(object sender, EventArgs e)
        {
            //label_updateStatus.Text = "DCS Stable Has Been Updated!";//making sure the text fits
        }
    }//end of public partial class Form1 : Form
}//end of namespace DCS_VersionUpdateNotifier