using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;
using System.Drawing;

namespace Hex_2048
{
  public class Preferences
    {
        const string conPreferencesFilename = "Hex2048_Preferences.bin";
        static string Filename { get { return formHex2048.WorkingDirectory + conPreferencesFilename; } }

        public static BinaryFormatter formatter = new BinaryFormatter();
        static Semaphore semIO = new Semaphore(1, 1);
        public static formHex2048 frmHex = null;
        public static Point ptLocation_Load = new Point();
        public static bool Abort = false;
        static public bool Load()
        {
            if (!System.IO.File.Exists(Filename))
                return false;
            semIO.WaitOne();
            {
                using (FileStream fs = new FileStream(Filename, FileMode.Open))
                {
                    // form dimensions
                    int intLeft = (int)formatter.Deserialize(fs);
                    int intTop = (int)formatter.Deserialize(fs);
                    float fltDeltaDrawSize = (float)formatter.Deserialize(fs);
                    frmHex.bolIgnoreFormChanges = true;
                    {
                        ptLocation_Load = new Point(intLeft, intTop);
                        formHex2048.DeltaDrawSize = fltDeltaDrawSize;
                    }
                    frmHex.bolIgnoreFormChanges = false;

                    Board.Populate();
                    // game state
                    for (int intX = 0; intX < formHex2048.szGame.Width; intX++)
                        for (int intY = 0; intY < formHex2048.szGame.Height; intY++)
                            Board.Tiles[intX, intY].Value = (int)formatter.Deserialize(fs);

                    // score 
                    formHex2048.Score = (int)formatter.Deserialize(fs);

                    // eFSM 
                    frmHex.eFSM = (enuHex2048_FSM)(int)formatter.Deserialize(fs);

                    // flareTriggers
                    formHex2048.lstFlareTrigger.Clear();
                    for (int intFTCounter = 0; intFTCounter < classTile.numColors; intFTCounter++)
                        formHex2048.lstFlareTrigger.Add((bool)formatter.Deserialize(fs));

                    // high score
                    formHex2048.intHighScore = (int)formatter.Deserialize(fs);
                    
                    // timer delay minutes 
                    formHex2048.lngTimerDelay_Minutes = (long)formatter.Deserialize(fs);

                    // challenge
                    classChallenge.intChallengesSolved = (int)formatter.Deserialize(fs);
                    int intNumChallengeTiles = (int)formatter.Deserialize(fs);
                    classChallenge.lstTiles.Clear();
                    classChallenge.ArrTiles = new classTile[formHex2048.szGame.Width, formHex2048.szGame.Height];

                    for (int intChallengeTileCounter = 0; intChallengeTileCounter < intNumChallengeTiles; intChallengeTileCounter++)
                    {
                        int intValue = (int)formatter.Deserialize(fs);
                        int intX = (int)formatter.Deserialize(fs);
                        int intY = (int)formatter.Deserialize(fs);
                        int intChallengeID = (int)formatter.Deserialize(fs);

                        Point pt = new Point(intX, intY);

                        classTile cTileNew = new classTile(pt);
                        classChallenge.ArrTiles[pt.X, pt.Y] = cTileNew;
                        classChallenge.ArrTiles[pt.X, pt.Y].Value = intValue;
                        classChallenge.ArrTiles[pt.X, pt.Y].intChallenge_GroupID = intChallengeID;

                        classChallenge.lstTiles.Add(cTileNew);
                    }

                    int intSecondsRemaining = (int)formatter.Deserialize(fs);
                    classChallenge.LivesRemaining = (int)formatter.Deserialize(fs);
                    
                    classChallenge.dtChallengeEnd = DateTime.Now.AddSeconds(intSecondsRemaining);
                    classChallenge.intNumBranches_Build = (int)formatter.Deserialize(fs);
                    classChallenge.intNumLevels_Build= (int)formatter.Deserialize(fs);

                    try
                    {

                        long lngTotalMilliseconds = (long)formatter.Deserialize(fs);
                        formHex2048.tsTimeSpan_TotalTimePlayed = TimeSpan.FromMilliseconds(lngTotalMilliseconds);
                    }
                    catch (Exception)
                    {

                    }

                    classChallenge.eState = classChallenge.enuChallengeState.ready;
                }
            }
            semIO.Release();

            return true;
        }
        

        static public void Save()
        {
            if (Abort) return;

            semIO.WaitOne();
            {
                if (System.IO.File.Exists(Filename))
                    System.IO.File.Delete(Filename);

                // create filestream
                using (FileStream fs = new FileStream(Filename, FileMode.Create))
                {
                    // form dimensions
                    formatter.Serialize(fs, (int)formHex2048.instance.Location.X);
                    formatter.Serialize(fs, (int)formHex2048.instance.Location.Y);
                    formatter.Serialize(fs, (float)formHex2048.DeltaDrawSize);

                    // game state
                    for (int intX =0; intX < formHex2048.szGame.Width; intX ++)
                        for (int intY =0; intY < formHex2048.szGame.Height; intY++)
                            formatter.Serialize(fs, (int)Board.Tiles[intX, intY].Value);

                    // score
                    formatter.Serialize(fs, (int)formHex2048.Score);

                    // FSM
                    formatter.Serialize(fs, (int)frmHex.eFSM);

                    // flareTriggers
                    for (int intFTCounter =0; intFTCounter < formHex2048.lstFlareTrigger.Count; intFTCounter++)
                        formatter.Serialize(fs, (bool)formHex2048.lstFlareTrigger[intFTCounter]);

                    // high score
                    formatter.Serialize(fs, (int)formHex2048.intHighScore);

                    // timer delay minutes
                    formatter.Serialize(fs, (long)formHex2048.lngTimerDelay_Minutes);

                    // challenges
                    formatter.Serialize(fs, (int)classChallenge.intChallengesSolved);
                    formatter.Serialize(fs, (int)classChallenge.lstTiles.Count);

                    //                                                      challenge state
                    for (int intChallengeTileCounter = 0; intChallengeTileCounter < classChallenge.lstTiles.Count; intChallengeTileCounter++)
                    {
                        classTile cTile = classChallenge.lstTiles[intChallengeTileCounter];
                        formatter.Serialize(fs, (int)cTile.Value);
                        formatter.Serialize(fs, (int)cTile.ID.X);
                        formatter.Serialize(fs, (int)cTile.ID.Y);
                        formatter.Serialize(fs, (int)cTile.intChallenge_GroupID);
                    }

                    // challenge time remaining 
                    formatter.Serialize(fs, (int)classChallenge.tsChallengeTimeRemaining.TotalSeconds);
                    formatter.Serialize(fs, (int)classChallenge.LivesRemaining);
                    formatter.Serialize(fs, (int)classChallenge.intNumBranches_Build);
                    formatter.Serialize(fs, (int)classChallenge.intNumLevels_Build);

                    // total time played 
                    formatter.Serialize(fs, (long)(formHex2048.tsTimeSpan_Total().TotalMilliseconds));
                }
            }
            semIO.Release();
        }
    }
}
