// Use Playtomic.

#define IDNET_PLAYTOMIC

#pragma warning disable

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using System.Text.RegularExpressions;
using UnityEngine.UI;


/// <summary>
///     Gui class for Idnet.
/// </summary>
public class IdnetGui : MonoBehaviour
{
    [Header("Login & Register panels")] 
    public GameObject LoginPanel;
    public GameObject RegisterPanel;
    public GameObject IDnetToY8Banner;

    [Header("AdsPlaceholder")]
    public GameObject AdsPlaceholder;

    [Header("Exclusive Menu")]
    public GameObject ExclusiveMenu;

    [Header("Register Email & Password Fields")]
    public InputField RegEmailField;

    public InputField RegPasswordField;
    public InputField RegNicknameField;
    public InputField RegFirstnameField;


    [Header("Login Email & Password Fields")]
    public InputField LoginEmailField;

    public InputField LoginPasswordField;


    [Header("Register Navigation Buttons")]
    public GameObject NextButton;

    public GameObject FinishButton;
    public GameObject PreviousButton;
    [Header("Register Menu Gameobjects")] 
    public GameObject Canvas;
    public GameObject[] RegisterFlowStates;
    public Button BoyButton;
    public Button GirlButton;
    public Dropdown MonthsList;
    public Dropdown YearList;
    public Text LoginTitle;
    public Text RegisterTitle;
    public Text LoginErrorDialog;
    public Text RegisterErrorDialog;
    public GameObject RegBottomPanel1;
    public GameObject RegBottomPanel2;
    public Image[] Dots;

    [HideInInspector] public int CurrentRegisterState = 0;

    public readonly Color IdnetBlue = new Color(24f / 256, 84f / 256, 165f / 256);
    public Texture BluePixel;

    /// <summary>
    ///     Controls the flow of the GUI system.
    /// </summary>
    public ClassFiniteStateMachine<GuiState> Cfsm = new ClassFiniteStateMachine<GuiState>();

    public Texture2D CloseButtonTexture;
    public Texture Y8AccountLogo;

    public Font Font;
    public Texture GreenPixel;

    /// <summary>
    ///     Colored boxes.
    /// </summary>
    public Texture GreyPixel;

    /// <summary>
    ///     Allow the user to interact with the Gui?
    ///     Excluding exit button, which is always available.
    /// </summary>
    public bool Interactable = true;

    public Texture LeftArrow;

    public Texture LoadingImage;


    [HideInInspector] public string PasswordField = "";
    public Texture RightArrow;

    public GUISkin Skin;
    public string StatusText = "";

    public Color StatusTextColor
    {
        get { return responseStyle.normal.textColor; }
        set { responseStyle.normal.textColor = value; }
    }

    private void Awake()
    {
        Cfsm.AddState(new ClosedState(this));
        Cfsm.AddState(new ClosingState(this));

        Cfsm.AddState(new AutoLoginState(this));
        Cfsm.AddState(new LoginState(this));
        Cfsm.AddState(new RegisterState(this));
        Cfsm.AddState(new ProfileState(this));
        Cfsm.AddState(new SecretState(this));

        Cfsm.AddState(new LeaderboardState(this));
        Cfsm.AddState(new ListAchievementsState(this));
        Cfsm.AddState(new ListUserLevelsState(this));

        Cfsm.SetState<ClosedState>();

        // Debug state changes.
        Cfsm.StateChanged += (previous, current) =>
        {
            CloseAllUGUIStates();
            //Debug.Log("IdnetGUI: From '" + previous.Title + "' to '" + current.Title + "'");
        };
    }

    private void Update()
    {
        Cfsm.UpdateActiveState();

        ShortcutKeysUGUI();

        if (!(Idnet.I.Gui.Cfsm.ActiveType == typeof(IdnetGui.LoginState) ||
              Idnet.I.Gui.Cfsm.ActiveType == typeof(IdnetGui.RegisterState)))
        {
            return;
        }

        if (!useGUILayout) return;

        if (Cfsm.ActiveState == null) return;

        Cfsm.ActiveState.ShowGui();
    }

    /// <summary>
    ///     Custom GUI callbacks for LoginRegister.
    /// </summary>
    /// <param name="user"></param>
    /// <param name="exception"></param>
    public void LoginRegisterGuiCallback(Idnet.User user, Exception exception)
    {
        // Ignore the callback if we've cancelled.
        if (Idnet.I.ClosedLoginRegister == null)
            return;

        // Tell user about exception.
        Idnet.I.LoginRegisterException = exception;

        Idnet.I.CloseGui();
    }

    /// <summary>
    ///     Custom shortcut keys for Profile(Logout) and direct Logout.
    /// </summary>
    private void ShortcutKeys()
    {
        var e = Event.current;
        if ((e.type == EventType.KeyDown && e.command && e.alt && e.shift && e.keyCode == KeyCode.A) ||
            (e.type == EventType.KeyDown && e.control && e.alt && e.shift && e.keyCode == KeyCode.A))
        {
            Idnet.I.SecretWindow();
        }

        if (e.type == EventType.KeyDown && e.shift && e.keyCode == KeyCode.P)
        {
            Idnet.I.Profile();
        }

        if (e.type == EventType.KeyDown && e.shift && e.keyCode == KeyCode.L)
        {
            Idnet.I.Logout();
        }
    }

    private void ShortcutKeysUGUI()
    {
        if (Idnet.I.IsShowingGui())
        {
            if (Input.GetKeyDown(KeyCode.Escape))
            {
                Idnet.I.CloseGui();
            }
        }
    }

    private void OnGUI()
    {
        if ((Idnet.I.Gui.Cfsm.ActiveType == typeof(IdnetGui.LoginState) ||
             Idnet.I.Gui.Cfsm.ActiveType == typeof(IdnetGui.RegisterState)))
        {
            return;
        }

        ShortcutKeys();
        if (!useGUILayout) return;

        if (Cfsm.ActiveState == null) return;

        Cfsm.ActiveState.ShowGui();
    }

    /// <summary>
    ///     Tell users that there is an issue with connectivity.
    /// </summary>
    public void ServerException(ServerException serverException)
    {
        Interactable = true;

        StatusTextColor = Color.red;
        StatusText = "Please check your connection. The server may be down for maintenance.";

#if DEVELOPMENT_BUILD
        StatusText += " " + serverException;
#endif
    }

    /// <summary>
    ///     Tell users we / they fucked up.
    /// </summary>
    public void ApiException(Exception exception)
    {
        Interactable = true;

        if (exception == null)
            return;

        if (exception.Message.Contains("key") || exception.Message.Contains("Key"))
            return;

        StatusTextColor = IdnetBlue;
        //      StatusText = exception.Message + ".. Please try again.";
        StatusText = exception.Message;


#if DEVELOPMENT_BUILD
        StatusText += " " + exception;
#endif
    }

    public void CloseAllUGUIStates()
    {
        LoginPanel.SetActive(false);
        RegisterPanel.SetActive(false);
        IDnetToY8Banner.SetActive(false);
    }

    public void SetDOBDropDowns()
    {
        Idnet.I.YearList.Clear();
        Idnet.I.MonthsList.Clear();
        MonthsList.ClearOptions();
        YearList.ClearOptions();

        Idnet.I.YearList.Add("Year");
        Idnet.I.MonthsList.Add("Month");

        for (int i = Idnet.I.CurrentYear; i >= Idnet.I.CurrentYear - 70; i--)
        {
            Idnet.I.YearList.Add(i.ToString());
        }

        string[] monthsArr =
        {
            "January", "Febrauary", "March", "April", "May", "June", "July", "August", "September", "October",
            "November", "December"
        };
        Idnet.I.MonthsList.AddRange(monthsArr);

        MonthsList.AddOptions(Idnet.I.MonthsList);
        YearList.AddOptions(Idnet.I.YearList);
    }

    void InitialiseInputFields()
    {
        string email = Idnet.User.Current.Email;
        string password = PasswordField;
        string nickname = string.IsNullOrEmpty(Idnet.User.Current.Nickname)
            ? string.Empty
            : Idnet.User.Current.Nickname;
        string firstname = string.IsNullOrEmpty(Idnet.User.Current.Firstname)
            ? string.Empty
            : Idnet.User.Current.Firstname;

        LoginEmailField.text = RegEmailField.text = email;
        LoginPasswordField.text = RegPasswordField.text = password;
        RegNicknameField.text = nickname;
        RegFirstnameField.text = firstname;

        MonthsList.value = 0;
        YearList.value = 0;

        SetIDnetToY8Banner(Idnet.I.EnableY8ToIDnetBanner);
    }

    public bool ValidateNickname(string str, bool? showErrorDialog = null)
    {
        if (!ValidateString(str) || str.Length < 2)
        {
            if (showErrorDialog != null)
            {
                StatusText = "Nickname must be at least 2 letters";
            }

            return false;
        }

        return true;
    }

    public bool ValidateFirstname(string str, bool? showErrorDialog = null)
    {
        /*
        if (!ValidateString(str) || str.Length < 2 ) {
            if (showErrorDialog != null) {
                StatusText = "First name must be at least 2 letters";
            }
            return false;
        }
        */
        return true;
    }


    public bool ValidatePassword(string str, bool? showErrorDialog = null)
    {
        if (!ValidateString(str) || str.Length < 6)
        {
            if (showErrorDialog != null)
            {
                if (showErrorDialog == true)
                {
                    StatusText = "Password must be 6 or more long";
                }
            }

            return false;
        }

        if (showErrorDialog != null)
        {
            if (showErrorDialog == false)
            {
                StatusText = string.Empty;
            }
        }

        return true;
    }


    public bool ValidateGender(string str, bool? showErrorDialog = null)
    {
        if (!ValidateString(str))
            return false;

        if ((!(str.Contains("Male") || str.Contains("Female"))))
        {
            if (showErrorDialog != null)
            {
                StatusText = "Please choose your Gender";
            }

            return false;
        }

        return true;
    }

    public bool ValidateBirthYear(string str, bool? showErrorDialog = null)
    {
        if (!ValidateString(str))
        {
            return false;
        }

        if (str.ToLower().Contains("year"))
        {
            if (showErrorDialog != null)
            {
                StatusText = "Please choose your birth year";
            }

            return false;
        }

        return true;
    }

    public bool ValidateBirthMonth(string str, bool? showErrorDialog = null)
    {
        if (!ValidateString(str))
        {
            return false;
        }

        if (str.ToLower().Contains("month"))
        {
            if (showErrorDialog != null)
            {
                StatusText = "Please choose your birth month";
            }

            return false;
        }

        return true;
    }

    bool ValidateEmail(string strIn, bool? showErrorDialog = null)
    {
        // Return true if strIn is in valid e-mail format.
        bool isValidEmail = Regex.IsMatch(strIn,
            @"^(?!\.)(""([^""\r\\]|\\[""\r\\])*""|"
            + @"([-a-z0-9!#$%&'*+/=?^_`{|}~]|(?<!\.)\.)*)(?<!\.)"
            + @"@[a-z0-9][\w\.-]*[a-z0-9]\.[a-z][a-z\.]*[a-z]$");

        if (!isValidEmail)
        {
            if (showErrorDialog != null)
            {
                StatusText = "Please enter valid email address";
            }
        }

        return isValidEmail;
    }

    bool ValidateString(string str)
    {
        if (string.IsNullOrEmpty(str))
        {
            return false;
        }

        return true;
    }


    public void LoginEmail(InputField email)
    {
        Idnet.User.Current.Email = email.text;
    }

    public void LoginPassword(InputField password)
    {
        PasswordField = password.text;
    }

    public void RegisterEmail(InputField email)
    {
        Idnet.User.Current.Email = email.text.ToLower();
        ValidateEmail(email.text.ToLower());
    }

    public void RegisterPassword(InputField password)
    {
        PasswordField = password.text;
        if (password.text.Length < 6)
        {
            ValidatePassword(password.text, true);
        }
        else
        {
            ValidatePassword(password.text, false);
        }
    }

    public void RegisterGender(string gender)
    {
        Idnet.User.Current.Gender = gender;
        if (ValidateGender(gender))
        {
            SetAvatar();
        }
    }

    public void RegisterBirthYear(Dropdown birthyear)
    {
        ValidateBirthYear(birthyear.options[birthyear.value].text);
        Idnet.User.Current.BirthYear = birthyear.options[birthyear.value].text;
    }

    public void RegisterBirthMonth(Dropdown birthmonth)
    {
        /*
        ValidateBirthMonth (birthmonth.options [birthmonth.value].text);
        Idnet.User.Current.BirthMonth = MonthsList.options.IndexOf(birthmonth.options[birthmonth.value].text) + 1;
        */
        string birthMonth = (birthmonth.value).ToString();
        ValidateBirthMonth(birthMonth);
        Idnet.User.Current.BirthMonth = birthMonth;
    }

    public void RegisterNickname(InputField nickName)
    {
        ValidateNickname(nickName.text);
        Idnet.User.Current.Nickname = nickName.text;
    }

    public void RegisterFirstname(InputField firstName)
    {
        ValidateFirstname(firstName.text);
        Idnet.User.Current.Firstname = firstName.text;
    }

    void ResetNavigationButtons()
    {
        StatusText = string.Empty;
        FinishButton.SetActive(false);
        RegBottomPanel1.SetActive(true);
        RegBottomPanel2.SetActive(false);
        NextButton.SetActive(true);
        NextButton.GetComponent<Button>().interactable = false;
        PreviousButton.SetActive(true);
        PreviousButton.GetComponent<Button>().interactable = true;
    }

    void ResetDots()
    {
        for (int i = 0; i < Dots.Length; i++)
        {
            Dots[i].color = new Color32(221, 221, 221, 255);
        }
    }

    void EnableDot(int dotNumber)
    {
        ResetDots();
        for (int i = 0; i < Dots.Length; i++)
        {
            if (i.Equals(dotNumber))
            {
                Dots[i].color = new Color32(234, 0, 0, 255);
            }
        }
    }

    public void ValidateRegisterFlowSteps()
    {
        ResetNavigationButtons();

        if (CurrentRegisterState < 0)
        {
            CurrentRegisterState = 0;
        }

        if (CurrentRegisterState > RegisterFlowStates.Length - 1)
        {
            CurrentRegisterState = RegisterFlowStates.Length - 1;
        }

        if (CurrentRegisterState.Equals(0))
        {
            //PreviousButton.GetComponent<Button> ().interactable = false;
            PreviousButton.SetActive(false);
        }

        if (CurrentRegisterState.Equals(RegisterFlowStates.Length - 1))
        {
            NextButton.SetActive(false);
            FinishButton.SetActive(true);
            FinishButton.GetComponent<Button>().interactable = false;
            RegBottomPanel1.SetActive(false);
            RegBottomPanel2.SetActive(true);
        }

        EnableDot(CurrentRegisterState);
    }


    void EnableNextButton(bool value)
    {
        if (NextButton.activeSelf)
        {
            NextButton.GetComponent<Button>().interactable = value;
        }
    }

    void EnableFinishButton(bool value)
    {
        if (FinishButton.activeSelf)
        {
            FinishButton.GetComponent<Button>().interactable = value;
        }
    }

    bool ValidateEnteredData(bool? showErrorDialog = null)
    {
        if (Idnet.I.Gui.Cfsm.ActiveType != typeof(IdnetGui.RegisterState))
        {
            return false;
        }

        if (CurrentRegisterState.Equals(0))
        {
            if (!(ValidateNickname(Idnet.User.Current.Nickname, showErrorDialog) &&
                  ValidateFirstname(Idnet.User.Current.Firstname, showErrorDialog)))
            {
                EnableNextButton(false);
                return false;
            }

            EnableNextButton(true);
        }
        else if (CurrentRegisterState.Equals(1))
        {
            if (!(ValidateEmail(Idnet.User.Current.Email, showErrorDialog) &&
                  ValidatePassword(PasswordField, showErrorDialog)))
            {
                EnableNextButton(false);
                return false;
            }

            EnableNextButton(true);
        }
        else if (CurrentRegisterState.Equals(2))
        {
            if (!ValidateGender(Idnet.User.Current.Gender, showErrorDialog))
            {
                EnableNextButton(false);
                return false;
            }

            EnableNextButton(true);
        }
        else if (CurrentRegisterState.Equals(3))
        {
            if (!(ValidateBirthMonth(Idnet.User.Current.BirthMonth, showErrorDialog) &&
                  ValidateBirthYear(Idnet.User.Current.BirthYear, showErrorDialog)))
            {
                EnableFinishButton(false);
                return false;
            }

            EnableFinishButton(true);
        }

        return true;
    }

    public void SetCurrentFlowState(int currentflowstate, Exception exception)
    {
        CurrentRegisterState = currentflowstate;
        DisableAllRegisterFlowStates();
        ValidateRegisterFlowSteps();
        RegisterFlowStates[currentflowstate].SetActive(true);
        ApiException(exception);
    }

    public void SetCurrentFlowState(int currentflowstate)
    {
        CurrentRegisterState = currentflowstate;
        DisableAllRegisterFlowStates();
        ValidateRegisterFlowSteps();
        RegisterFlowStates[currentflowstate].SetActive(true);
    }

    public void RegisterFinish()
    {
        Idnet.I.Register(Idnet.User.Current.Email, PasswordField, Idnet.User.Current.Nickname,
            LoginRegisterGuiCallback);
    }

    public void LoginFinish()
    {
        if (!(ValidateString(Idnet.User.Current.Email) && ValidateString(PasswordField)))
        {
            StatusText = "Email & Password required";
            return;
        }

        Idnet.I.Login(Idnet.User.Current.Email, PasswordField, LoginRegisterGuiCallback);
    }

    public void SetLoginState()
    {
        Cfsm.SetState<LoginState>();
    }

    public void SetRegisterState()
    {
        Cfsm.SetState<RegisterState>();
    }


    public void RegisterNext()
    {
        if (!ValidateEnteredData(true))
        {
            return;
        }

        CurrentRegisterState += 1;

        ValidateRegisterFlowSteps();


        RegisterFlowStates[CurrentRegisterState - 1].SetActive(false);
        RegisterFlowStates[CurrentRegisterState].SetActive(true);

        if (CurrentRegisterState == 2)
        {
            LoadAvatar();
        }
    }

    void LoadAvatar()
    {
        ResetAvatar();
        if (!string.IsNullOrEmpty(Idnet.User.Current.Gender))
        {
            if (Idnet.User.Current.Gender.ToLower().Equals("female"))
            {
                GirlButton.gameObject.GetComponent<Image>().sprite = GirlButton.spriteState.highlightedSprite;
            }
            else if (Idnet.User.Current.Gender.ToLower().Equals("male"))
            {
                BoyButton.gameObject.GetComponent<Image>().sprite = BoyButton.spriteState.highlightedSprite;
            }
        }
    }

    void SetAvatar()
    {
        ResetAvatar();
        if (Idnet.User.Current.Gender.ToLower().Equals("female"))
        {
            GirlButton.gameObject.GetComponent<Image>().sprite = GirlButton.spriteState.highlightedSprite;
        }
        else if (Idnet.User.Current.Gender.ToLower().Equals("male"))
        {
            BoyButton.gameObject.GetComponent<Image>().sprite = BoyButton.spriteState.highlightedSprite;
        }
    }


    void ResetAvatar()
    {
        GirlButton.gameObject.GetComponent<Image>().sprite = GirlButton.spriteState.disabledSprite;
        BoyButton.gameObject.GetComponent<Image>().sprite = BoyButton.spriteState.disabledSprite;
    }

    public void RegisterPrevious()
    {
        CurrentRegisterState -= 1;
        ValidateRegisterFlowSteps();


        RegisterFlowStates[CurrentRegisterState + 1].SetActive(false);
        RegisterFlowStates[CurrentRegisterState].SetActive(true);

        if (CurrentRegisterState == 2)
        {
            LoadAvatar();
        }
    }

    public void SetIDnetToY8Banner(bool enable)
    {
        var yPos = 0.0f;
        if (enable)
        {
            yPos = -36.4f;
        }
        else
        {
            yPos = 0.0f;
        }

        IDnetToY8Banner.SetActive(enable);
        Idnet.I.EnableY8ToIDnetBanner = enable;
        LoginPanel.transform.localPosition = new Vector3(0, yPos, 0);
        RegisterPanel.transform.localPosition = new Vector3(0, yPos, 0);
    }

    public void DisableAllRegisterFlowStates()
    {
        for (int i = 0; i < RegisterFlowStates.Length; i++)
        {
            RegisterFlowStates[i].SetActive(false);
        }
    }

    public class AutoLoginState : GuiState
    {
        public AutoLoginState(IdnetGui gui) : base(gui)
        {
        }

        public override string Title
        {
            get { return "Browser Auto-Login"; }
        }

        protected override void Enter()
        {
            Gui.StatusTextColor = Color.grey;
            Gui.StatusText = "Attempting to login using the browser. Please wait.";
            Gui.Interactable = false;
        }

        protected override void CustomGui()
        {
        }

        protected override void Exit()
        {
            Gui.Interactable = true;
        }
    }

    /// <summary>
    ///     Allows the user to login.
    /// </summary>
    public class LoginState : GuiState
    {
        public LoginState(IdnetGui gui) : base(gui)
        {
        }

        public override string Title
        {
            //1.5.0
            get
            {
                string TitleText = "Login";
                if (string.IsNullOrEmpty(Idnet.I.GameName))
                {
                    //TitleText = "Login";
                }
                else if (Idnet.I.GameName.Length > 20)
                {
                    //TitleText = "Login";
                }
                else
                {
                    TitleText += " on " + Idnet.I.GameName;
                }

                return TitleText;
            }
        }

        protected override void Enter()
        {
            /*
            Gui.StatusTextColor = Color.grey;
            Gui.StatusText = "id.net login. Please enter your details below.";
            */
            if (!Gui.LoginPanel.activeSelf)
            {
                Gui.LoginPanel.SetActive(true);
                Gui.LoginTitle.text = Title;
                Gui.StatusText = string.Empty;
                Gui.InitialiseInputFields();
            }
        }

        protected override void CustomGui()
        {
            Gui.LoginErrorDialog.text = Gui.StatusText;
            Gui.Canvas.GetComponent<CanvasGroup>().interactable = Gui.Interactable;

            /*
            UpdateSmallRects();
            const int buttonOffset = 70;

            GUI.skin.settings.selectionColor = Color.grey;
            GUI.skin.settings.doubleClickSelectsWord = true;
            GUI.skin.settings.cursorFlashSpeed = 1f;

            var dynamicRect = EmailNicknamePasswordFields();

            const int diff = 40;
            dynamicRect.height *= 2;

            //changing font size of Login text
            Gui.loginButStyle.fontSize = 17;

            
            //GUI.enabled = Gui.Interactable && Idnet.User.Current.Email.Length > 4 && Gui.PasswordField.Length > 4;


            GUI.enabled = Gui.Interactable;

            if (GUI.Button(new Rect(ScreenCenter.x + 43, ScreenCenter.y + 24, 190, 35), "Login",
                Gui.loginButStyle))
            {
                Idnet.I.Login(Idnet.User.Current.Email, Gui.PasswordField, Gui.LoginRegisterGuiCallback);
            }

            //reverting vack the original size
            Gui.loginButStyle.fontSize = 15;

            dynamicRect.height /= 2;
            dynamicRect.y += diff + 30;

            GUI.enabled = Gui.Interactable;

            //Open idnet link in new tab GUI workaround.
            var E = Event.current;
            var R = new Rect(ScreenCenter.x + 58, ScreenCenter.y + 60, 80, 15);
            if (E.type == EventType.MouseDown && R.Contains(E.mousePosition))
            {
#if UNITY_WEBGL
                var url = "https://account.y8.com/accounts/password/new";
                Idnet.I.OpenLink(url);
#else
                Application.OpenURL("https://account.y8.com/accounts/password/new");
#endif
            }

            Gui.linkStyle.fontSize = 12;

            // Password recovery.
            GUI.Button(new Rect(ScreenCenter.x + 62, ScreenCenter.y + 68, 80, 15), "Forgot Password?",
                Gui.linkStyle);

            Gui.linkStyle.fontSize = 13;

            GUI.DrawTexture(new Rect(ScreenCenter.x + 53, ScreenCenter.y + 82, 96, 1.0f), Gui.BluePixel);

            dynamicRect.x -= buttonOffset;


            dynamicRect.y += diff;

            // Navigation to registration.
            GUI.Label(new Rect(ScreenCenter.x - 57, ScreenCenter.y + 107, 190, 20), "Don't have an account?");

            if (GUI.Button(new Rect(ScreenCenter.x + 74, ScreenCenter.y + 110, 125, 18), "Create an Account",
                Gui.linkStyle))
            {
                Gui.Cfsm.SetState<RegisterState>();
            }
            dynamicRect.x -= buttonOffset;

            GUI.DrawTexture(new Rect(ScreenCenter.x + 83, ScreenCenter.y + 126, 109, 1.0f), Gui.BluePixel);
            */
        }

        protected override void Exit()
        {
            Idnet.User.Current.SaveLocally();
        }
    }


    /// <summary>
    ///     SecretState.
    /// </summary>
    public class SecretState : GuiState
    {
        public SecretState(IdnetGui gui) : base(gui)
        {
        }

        public override string Title
        {
            get { return "Secret Menu"; }
        }

        protected override void Enter()
        {
            Gui.StatusTextColor = Color.grey;
            Gui.StatusText = "";
        }

        protected override void CustomGui()
        {
            var yOffset = 145;
            UpdateRects();
            GUI.enabled = true;

            GUI.skin.label.fontSize = 12;

            GUI.Label(new Rect(ScreenCenter.x - 50, ScreenCenter.y - yOffset, 95, 20), "App Name");

            GUI.TextField(new Rect(ScreenCenter.x + 48, ScreenCenter.y - yOffset, 175, 18), Idnet.I.GameName);

            yOffset -= 22;

            GUI.Label(new Rect(ScreenCenter.x - 50, ScreenCenter.y - yOffset, 95, 20), "App Id");
            GUI.TextField(new Rect(ScreenCenter.x + 48, ScreenCenter.y - yOffset, 175, 18), Idnet.AppId);

            yOffset -= 22;

            GUI.Label(new Rect(ScreenCenter.x - 50, ScreenCenter.y - yOffset, 95, 20), "Sdk-Version");
            GUI.TextField(new Rect(ScreenCenter.x + 48, ScreenCenter.y - yOffset, 175, 18), Idnet.SdkVersion);

            yOffset -= 22;
            GUI.Label(new Rect(ScreenCenter.x - 50, ScreenCenter.y - yOffset, 100, 20), "Unity-Version");
            GUI.TextField(new Rect(ScreenCenter.x + 48, ScreenCenter.y - yOffset, 175, 18), Application.unityVersion);

            yOffset -= 22;
            GUI.Label(new Rect(ScreenCenter.x - 50, ScreenCenter.y - yOffset, 100, 20), "Api Calls Count");
            GUI.TextField(new Rect(ScreenCenter.x + 48, ScreenCenter.y - yOffset, 175, 18),
                Idnet.ApiCallsCounter.ToString());

            yOffset -= 22;

            GUI.Label(new Rect(ScreenCenter.x - 50, ScreenCenter.y - yOffset, 110, 20), "Y8 Network?");
            GUI.TextField(new Rect(ScreenCenter.x + 48, ScreenCenter.y - yOffset, 175, 18),
                Idnet.I.IsSponsor.ToString());

            yOffset -= 22;

            GUI.Label(new Rect(ScreenCenter.x - 50, ScreenCenter.y - yOffset, 110, 20), "Localhost test?");
            GUI.TextField(new Rect(ScreenCenter.x + 48, ScreenCenter.y - yOffset, 175, 18),
                Idnet.I.EnableLocalhostTest.ToString());

            yOffset -= 22;

            GUI.Label(new Rect(ScreenCenter.x - 70, ScreenCenter.y - yOffset, 150, 20), "Blacklisted Domain?");
            GUI.TextField(new Rect(ScreenCenter.x + 48, ScreenCenter.y - yOffset, 175, 18),
                Idnet.I.IsBlacklisted.ToString());
            yOffset -= 22;

            GUI.Label(new Rect(ScreenCenter.x - 50, ScreenCenter.y - yOffset, 100, 20), "Domain Name");
            GUI.TextField(new Rect(ScreenCenter.x + 48, ScreenCenter.y - yOffset, 175, 18),
                Idnet.I.RefererDomain);
            yOffset -= 30;

            GUI.enabled = true;
            if (GUI.Button(new Rect(ScreenCenter.x - 78, ScreenCenter.y - yOffset, 170, 30), "Clear Unity's Cache",
                Gui.loginButStyle))
            {
                PlayerPrefs.DeleteAll();
                PlayerPrefs.Save();
                // Caching.CleanCache();
            }

            if (GUI.Button(new Rect(ScreenCenter.x + 98, ScreenCenter.y - yOffset, 170, 30), "Reset IDnet Progress",
                Gui.loginButStyle))
            {
                PlayerPrefs.DeleteAll();
                PlayerPrefs.Save();
                // Caching.CleanCache();
                Idnet.I.DeleteAllProgress();
            }

            yOffset -= 38;
            if (GUI.Button(new Rect(ScreenCenter.x - 78, ScreenCenter.y - yOffset, 170, 30), "Leaderboard",
                Gui.loginButStyle))
            {
                Playtomic.LeaderboardsTable.GetTableName((tableName, response) =>
                {
                    if (response.success)
                    {
                        if (!string.IsNullOrEmpty(tableName))
                            Idnet.I.Leaderboard(tableName);
                        else
                            Idnet.I.Leaderboard("Table Not Found!!");
                    }
                });
            }

            if (GUI.Button(new Rect(ScreenCenter.x + 98, ScreenCenter.y - yOffset, 170, 30), "Achievements",
                Gui.loginButStyle))
            {
                Idnet.I.ListAchievements();
            }

            yOffset -= 38;
            if (Idnet.User.LoggedIn())
            {
                if (GUI.Button(new Rect(ScreenCenter.x - 78, ScreenCenter.y - yOffset, 170, 30), "Logout",
                    Gui.loginButStyle))
                {
                    Idnet.I.Logout();
                }
                if (!Idnet.I.ShowRealAdvert)
                {
                    if (GUI.Button(new Rect(ScreenCenter.x + 98, ScreenCenter.y - yOffset, 170, 30), "Disable Placeholder",
                        Gui.loginButStyle))
                    {
                        Idnet.I.ShowRealAdvert = true;
                    }
                }
                else
                {
                    if (GUI.Button(new Rect(ScreenCenter.x + 98, ScreenCenter.y - yOffset, 170, 30), "Enable Placeholder",
                       Gui.loginButStyle))
                    {
                        Idnet.I.ShowRealAdvert = false;
                    }
                }
            }
            else
            {
                GUI.Label(new Rect(ScreenCenter.x + 0, ScreenCenter.y - yOffset, 300, 30),
                    "User not logged-in to id.net sdk");
            }

            yOffset -= 38;

            if (Idnet.ApiCallsCounter >= 150)
                GUI.Label(new Rect(ScreenCenter.x - 80, ScreenCenter.y - yOffset, 350, 30),
                    "<color=red>Warning: Too many id.net Api calls in last 5 minutes,hence blocking next ones.</color>");

            GUI.skin.settings.selectionColor = Color.gray;
            GUI.skin.settings.doubleClickSelectsWord = true;
            GUI.skin.settings.cursorFlashSpeed = 1f;
        }
    }

    /// <summary>
    ///     Allows the user to register.
    /// </summary>
    public class RegisterState : GuiState
    {
        public RegisterState(IdnetGui gui) : base(gui)
        {
        }

        public override string Title
        {
            get
            {
                string TitleText = "Register";
                if (string.IsNullOrEmpty(Idnet.I.GameName))
                {
                    //TitleText = "Register";
                }
                else if (Idnet.I.GameName.Length > 20)
                {
                    //TitleText = "Register";
                }
                else
                {
                    TitleText += " on " + Idnet.I.GameName;
                }

                return TitleText;
            }
        }

        protected override void Enter()
        {
            /*
            Gui.StatusTextColor = Color.grey;
            Gui.StatusText = "id.net registration. Please enter your details below.";
            */

            if (!Gui.RegisterPanel.activeSelf)
            {
                Gui.ValidateRegisterFlowSteps();
                Gui.RegisterPanel.SetActive(true);
                Gui.RegisterTitle.text = Title;
                Gui.StatusText = string.Empty;
                Gui.InitialiseInputFields();
            }
        }

        protected override void CustomGui()
        {
            if (Time.frameCount % 2 == 0)
            {
                Gui.ValidateEnteredData();
            }

            Gui.RegisterErrorDialog.text = Gui.StatusText;
            Gui.Canvas.GetComponent<CanvasGroup>().interactable = Gui.Interactable;

            /*
            UpdateSmallRects();
            const int buttonOffset = 70;
            var dynamicRect = EmailNicknamePasswordFields(includeNicknameField: true);

            const int diff = 40;

            GUI.enabled = Gui.Interactable;

            dynamicRect.height *= 2;

            //changing font size of Register text
            Gui.registerButStyle.fontSize = 17;

            if (GUI.Button(new Rect(ScreenCenter.x + 43, ScreenCenter.y + 62, 190, 32), "Register",
                Gui.registerButStyle))
            {
                Idnet.I.Register(Idnet.User.Current.Email, Gui.PasswordField, Idnet.User.Current.Nickname,
                    Gui.LoginRegisterGuiCallback);
            }

            //reverting back the original size
            Gui.registerButStyle.fontSize = 15;

            dynamicRect.height /= 2;

            dynamicRect.y += diff + 30;

            GUI.enabled = Gui.Interactable;

            // Navigation back to login.
            GUI.Label(new Rect(ScreenCenter.x - 51, ScreenCenter.y + 107, 190, 20), "Already have an account?");
            dynamicRect.x += buttonOffset;
            if (GUI.Button(new Rect(ScreenCenter.x + 61, ScreenCenter.y + 110, 125, 18), "Login",
                Gui.linkStyle))
            {
                Gui.Cfsm.SetState<LoginState>();
            }
            dynamicRect.x -= buttonOffset;

            GUI.DrawTexture(new Rect(ScreenCenter.x + 107, ScreenCenter.y + 126, 35, 1.0f), Gui.BluePixel);


            dynamicRect.y += diff;
            */
        }

        protected override void Exit()
        {
            Gui.SetCurrentFlowState(0);
            Idnet.User.Current.SaveLocally();
        }
    }

    public class ProfileState : GuiState
    {
        public ProfileState(IdnetGui gui) : base(gui)
        {
        }

        public override string Title
        {
            get { return "PROFILE"; }
        }

        protected override void Enter()
        {
            Gui.StatusTextColor = Color.grey;
            Gui.StatusText = "You are logged into to id.net.";
        }

        protected override void CustomGui()
        {
            UpdateSmallRects();
            var dynamicRect = EmailNicknamePasswordFields(includeNicknameField: true, readOnly: true);

            dynamicRect.height *= 2;
            GUI.enabled = Gui.Interactable;
            if (GUI.Button(new Rect(ScreenCenter.x + 40, ScreenCenter.y + 25, 170, 30), "LOGOUT", Gui.loginButStyle))
            {
                Idnet.I.Logout();

                Gui.Cfsm.SetState<ClosingState>();
            }
        }
    }

    /// <summary>
    ///     Shows the leaderboards.
    /// </summary>
    public class LeaderboardState : GuiState
    {
        public LeaderboardState(IdnetGui gui)
            : base(gui)
        {
        }

        public override string Title
        {
            get
            {
                if (Idnet.I.LeaderboardTable == null || Idnet.I.LeaderboardTable == "highscores")
                {
                    return "LEADERBOARD";
                }

                return Idnet.I.LeaderboardTable;
            }
        }

        protected override void Enter()
        {
            Gui.StatusTextColor = Color.grey;
            Gui.StatusText = "";
        }


        protected override void CustomGui()
        {
            UpdateRects();
            // Highscores.
            var highscores = Idnet.I.Highscores;
            const int textHeight = 18;
            var yOffset = -15;

            var startScoreNumber = (Idnet.I.LeaderboardPage - 1) * Idnet.HighscoresPerLeaderboardPage + 1;

#if IDNET_PLAYTOMIC
            var endScoreNumber = startScoreNumber + highscores.Count - 1;
#else // Clamp end index to the number of entries so we don't get a bounds exception.
            var endScoreNumber = startScoreNumber + Idnet.HIGHSCORES_PER_LEADERBOARD_PAGE - 1;
            endScoreNumber = Mathf.Min(endScoreNumber, highscores.Count);
#endif

            // Widths.
            var nameSpace = ContentRect.width;
            const int number = 85;
            nameSpace -= number;
            const int score = 112;
            nameSpace -= score;
            const int date = 85;
            nameSpace -= date;

            GUI.skin.label.alignment = TextAnchor.UpperLeft;

            GUI.skin.label.fontSize = 12;

            // ReSharper disable once JoinDeclarationAndInitializer
            float buttonWidths;
#if IDNET_PLAYTOMIC
            // Cycle mode buttons.
            if (Idnet.User.LoggedIn())
            {
                buttonWidths = ContentRect.width / 4.58f;

                DrawLeaderboardModeButton(ContentRect.y + yOffset, buttonWidths, textHeight, "Today", 0);

                DrawLeaderboardModeButton(ContentRect.y + yOffset, buttonWidths, textHeight, "7 Days", 1);

                DrawLeaderboardModeButton(ContentRect.y + yOffset, buttonWidths, textHeight, "30 Days", 2);

                DrawLeaderboardModeButton(ContentRect.y + yOffset, buttonWidths, textHeight, "All Time", 3);

                //            DrawLeaderboardModeButton(ContentRect.y + yOffset, buttonWidths, textHeight, "Today", 4);
            }

#endif
            yOffset += textHeight + textHeight + textHeight / 2;

            GUI.skin.label.fontSize = 20;
            GUI.skin.font = Gui.Font;
            GUI.skin.label.alignment = TextAnchor.MiddleLeft;

            Gui.leaderboardeStyle.alignment = TextAnchor.MiddleLeft;
            Gui.leaderboardeStyle.fontSize = 20;

            // Highest score.
            if (Idnet.User.LoggedIn())
            {
                if (Idnet.I.TimerLeaderboard == false)
                {
                    GUI.Label(
                        new Rect(ContentRect.x + 62, ContentRect.y + yOffset + 0, ContentRect.width / 1.3f,
                            textHeight * 2),
                        "<color=grey>Personal best:</color><color=#335EA7> " + Idnet.User.Current.BestScore +
                        "</color>",
                        Gui.leaderboardeStyle);
                }
                else
                {
                    //Converting time in Minutes:Seconds:Milliseconds
                    var t = TimeSpan.FromSeconds(Idnet.User.Current.BestScore / 1000);
                    var time = string.Format("{0:D2}:{1:D2}:{2:D3}", t.Minutes, t.Seconds,
                        Idnet.User.Current.BestScore - Idnet.User.Current.BestScore / 1000 * 1000);

                    if (t.ToString() == "00:00:000")
                        GUI.Label(
                            new Rect(ContentRect.x + 62, ContentRect.y + yOffset + 0, ContentRect.width / 1.3f,
                                textHeight * 2),
                            "<color=grey>Personal best: " + "--:--:--" + "</color>", Gui.leaderboardeStyle);
                    else
                        GUI.Label(
                            new Rect(ContentRect.x + 62, ContentRect.y + yOffset + 0, ContentRect.width / 1.3f,
                                textHeight * 2),
                            "<color=grey>Personal best:</color><color=#335EA7> " + time + "</color>",
                            Gui.leaderboardeStyle);
                }
            }
            else
            {
                if (Idnet.User.Current.CurrentScore != 0)
                    GUI.Label(
                        new Rect(ContentRect.x + 62, ContentRect.y + yOffset + 0, ContentRect.width / 1.3f,
                            textHeight * 2),
                        "<color=grey>Recent score:</color><color=#335EA7> " + Idnet.User.Current.CurrentScore +
                        "</color>", Gui.leaderboardeStyle);
                else
                    GUI.Label(
                        new Rect(ContentRect.x + 62, ContentRect.y + yOffset + 0, ContentRect.width / 1.3f,
                            textHeight * 2),
                        "<color=grey>Recent score:</color><color=#335EA7>  None yet</color>", Gui.leaderboardeStyle);
            }

            Gui.leaderboardeStyle.alignment = TextAnchor.UpperLeft;
            Gui.leaderboardeStyle.fontSize = 0;


            GUI.skin.label.alignment = TextAnchor.MiddleCenter;

            GUI.color = Color.white;

            //            changing font size of Register text
            Gui.registerButStyle.fontSize = 16;

            if (highscores.Count >= 0)
            {
                if (!Idnet.User.LoggedIn())
                {
                    if (GUI.Button(new Rect(ScreenCenter.x + 7.6f, ScreenCenter.y - 133, 180, 30), "Register to submit",
                        Gui.registerButStyle))
                    {
                        Idnet.I.CloseGui();
                        UpdateSmallRects();
                        Idnet.I.Register(loginRegisterException =>
                        {
                            if (loginRegisterException == null)
                            {
                                if (Idnet.User.LoggedIn())
                                {
                                    Debug.Log("User logged in: Nickname: " + Idnet.User.Current.Nickname);
                                    if (Idnet.User.Current.CurrentScore != 0)
                                    {
                                        if (Idnet.I.LeaderboardTable == null ||
                                            Idnet.I.LeaderboardTable == "highscores" ||
                                            Idnet.I.LeaderboardTable == "default" ||
                                            Idnet.I.LeaderboardTable == "Default")
                                        {
                                            Idnet.I.PostHighscore(Idnet.User.Current.CurrentScore);
                                        }
                                        else
                                        {
                                            Idnet.I.PostHighscore(Idnet.User.Current.CurrentScore,
                                                Idnet.I.LeaderboardTable);
                                        }
                                    }
                                }
                            }
                        });
                    }
                }
            }

            //reverting back the original size
            Gui.registerButStyle.fontSize = 15;

            yOffset += textHeight * 2 + textHeight / 3;

            // Iterate, drawing labels as we go.
#if IDNET_PLAYTOMIC
            for (var i = 0; i < highscores.Count; i++)
#else
            for (var i = startIndex; i < highscores.Count; i++)
#endif
            {
                // Make sure they have a valid nickname.
                var nickname = highscores[i].Nickname;
                if (string.IsNullOrEmpty(nickname))
                    nickname = "Anonymous";


                var scoreNumber = i;
#if IDNET_PLAYTOMIC
                scoreNumber += startScoreNumber;
#else
                scoreNumber += 1;
#endif

                // Highlight the player.
                // Gui.leaderboardeStyle.normal.textColor = Idnet.User.Current.Pid == highscores[i].Pid ? Gui.IdnetBlue : Color.black;
                Gui.leaderboardeStyle.normal.textColor = Idnet.User.Current.Pid == highscores[i].Pid
                    ? Color.grey
                    : Color.black;


                GUI.Label(new Rect(ContentRect.x + number / 2.7f, ContentRect.y + yOffset, number, textHeight),
                    "<color=grey>" + scoreNumber + ".</color>", Gui.leaderboardeStyle);

                //make usernames blue(user profile links)
                Gui.leaderboardelinkStyle.normal.textColor = Gui.IdnetBlue;
                Gui.leaderboardelinkStyle.fontSize = 14;

                var E = Event.current;
                var R = new Rect(ContentRect.x + number / 1.35f, ContentRect.y + yOffset, nameSpace, textHeight);
                if (E.type == EventType.MouseDown && R.Contains(E.mousePosition))
                {
#if UNITY_WEBGL
                    var url = "https://account.y8.com/profiles/" + highscores[i].Pid.ToString();
                    Idnet.I.OpenLink(url);
#else
                    Application.OpenURL("https://account.y8.com/profiles/" + highscores[i].Pid);
#endif
                }

                if (nickname.Length > 14) nickname = nickname.Substring(0, 14);
                GUI.Button(new Rect(ContentRect.x + number / 1.35f, ContentRect.y + yOffset, nameSpace, textHeight),
                    nickname, Gui.leaderboardelinkStyle);

                Gui.leaderboardeStyle.alignment = TextAnchor.UpperRight;
                if (Idnet.I.TimerLeaderboard == false)
                {
                    GUI.Label(
                        new Rect(ContentRect.x + number + nameSpace / 3 + nameSpace / 10, ContentRect.y + yOffset,
                            score,
                            textHeight),
                        highscores[i].Score.ToString(), Gui.leaderboardeStyle);
                }
                else
                {
                    //Converting time in Minutes:Seconds:Milliseconds
                    var t = TimeSpan.FromSeconds((int)(highscores[i].Score / 1000));
                    var time = string.Format("{0:D2}:{1:D2}:{2:D3}", t.Minutes, t.Seconds,
                        (int)(highscores[i].Score - (int)(highscores[i].Score / 1000) * 1000));

                    GUI.Label(
                        new Rect(ContentRect.x + number + nameSpace / 3 + nameSpace / 10, ContentRect.y + yOffset,
                            score,
                            textHeight),
                        time, Gui.leaderboardeStyle);
                }

                Gui.leaderboardeStyle.alignment = TextAnchor.UpperRight;
                GUI.Label(
                    new Rect(ContentRect.x + number / 1.06f + nameSpace + date, ContentRect.y + yOffset, date,
                        textHeight),
                    "<color=grey>" + highscores[i].RDate.ToUpper() + "</color>", Gui.leaderboardeStyle);

                Gui.leaderboardeStyle.alignment = TextAnchor.UpperLeft;

                yOffset += textHeight + textHeight / 10;
            }

            yOffset = 273;
            Gui.leaderboardeStyle.normal.textColor = Color.black;

            //1.5.0
            //Page number font size
            GUI.skin.label.fontSize = 15;
            //Page number
            buttonWidths = ContentRect.width / 2.8f;

            GUI.Label(new Rect(ContentRect.x + buttonWidths, ContentRect.y + yOffset, score, textHeight * 2),
                "page " + Idnet.I.LeaderboardPage);

            //font size original size back.
            GUI.skin.label.fontSize = 12;

            // Previous and next page buttons.
            GUI.enabled = Gui.Interactable && startScoreNumber > 1;
            //1.5.0
            buttonWidths = ContentRect.width / 3.2f;
            if (startScoreNumber > 1)
            {
                if (
                    GUI.Button(
                        new Rect(ContentRect.x + buttonWidths + 31, ContentRect.y + yOffset + 11.2f,
                            Gui.LeftArrow.width,
                            Gui.LeftArrow.height),
                        Gui.LeftArrow, Gui.linkStyle))
                {
                    Idnet.I.LeaderboardPage--;

#if IDNET_PLAYTOMIC
                    Idnet.I.RefreshLeaderboard();
#endif
                }
            }

#if IDNET_PLAYTOMIC
            GUI.enabled = Gui.Interactable && highscores.Count >= Idnet.HighscoresPerLeaderboardPage;
#else
            GUI.enabled = Gui.Interactable &&  endScoreNumber <= highscores.Count;
#endif
            //1.5.0
            if (highscores.Count >= Idnet.HighscoresPerLeaderboardPage)
            {
                if (
                    GUI.Button(
                        new Rect(ContentRect.x + buttonWidths + buttonWidths - 15, ContentRect.y + yOffset + 11.2f,
                            Gui.RightArrow.width, Gui.RightArrow.height),
                        Gui.RightArrow, Gui.linkStyle))
                {
                    Idnet.I.LeaderboardPage++;

#if IDNET_PLAYTOMIC
                    Idnet.I.RefreshLeaderboard();
#endif
                }
            }

            GUI.enabled = Gui.Interactable;
            GUI.skin.label.alignment = TextAnchor.MiddleLeft;
        }

        private void DrawLeaderboardModeButton(float bottom, float buttonWidths, int textHeight, string text, int index)
        {
            var isCurrentMode = (int)Idnet.I.LeaderboardModeValue == index;
            Gui.modeButtonStyle.normal.background = isCurrentMode
                ? (Texture2D)Gui.GreenPixel
                : (Texture2D)Gui.BluePixel;
            if (
                GUI.Button(
                    new Rect(ContentRect.x + buttonWidths * index * 1.112f + 10, bottom, buttonWidths,
                        textHeight * 1.7f),
                    text, Gui.modeButtonStyle))
            {
                Idnet.I.LeaderboardModeValue = (Idnet.LeaderboardMode)index;

                if (!isCurrentMode)
                    Idnet.I.LeaderboardPage = 1;

                Idnet.I.RefreshLeaderboard();
            }
        }

        //1.5.0
        /*
        public void LeaderboardsUpdated(List<Highscore> highscores)
        {
            Gui.StatusTextColor = Color.grey;
            Gui.StatusText = highscores.Count + " highscores loaded.";
        }
        */

        public void LeaderboardsUpdated(List<Highscore> highscores)
        {
            Gui.StatusTextColor = Color.white;
            Gui.StatusText = "";
        }
    }

    /// <summary>
    ///     Shows all the users achievements.
    /// </summary>
    public class ListAchievementsState : GuiState
    {
        private const float SMALL_BORDER = 10;
        private const float ACHIEVEMENT_HEIGHT = 85;
        private const float ACHIEVEMENT_SPACE = 5;
        private const int ACHIEVEMENT_BORDER = 5;
        private const int ACHIEVEMENT_BORDER_X2 = ACHIEVEMENT_BORDER * 2;
        private List<PlayerAchievement> _achievements;
        private Rect _contentRect;
        private Vector2 _scrollDelta;
        private Rect _scrollViewRect;

        public ListAchievementsState(IdnetGui gui)
            : base(gui)
        {
        }

        public override string Title
        {
            get { return "Achievements"; }
        }

        protected override void Enter()
        {
            Gui.StatusTextColor = Color.grey;
            Gui.StatusText = "";
        }

        protected override void CustomGui()
        {
            UpdateRects();

            if (!Idnet.User.LoggedIn())
            {
                if (GUI.Button(new Rect(ScreenCenter.x + 9, ScreenCenter.y - 156, 170, 30), "REGISTER",
                    Gui.registerButStyle))
                {
                    Idnet.I.CloseGui();
                    UpdateSmallRects();
                    Idnet.I.Register(loginRegisterException =>
                    {
                        if (loginRegisterException == null)
                        {
                            if (Idnet.User.LoggedIn())
                            {
                                Debug.Log("User logged in: Nickname: " + Idnet.User.Current.Nickname);
                            }
                        }
                    });
                }
            }

            if (_achievements != null && _achievements.Count > 0)
                DisplayAchievements(_achievements);
        }

        /// <summary>
        ///     Display the achievements.
        /// </summary>
        /// <param name="achievements"></param>
        private void DisplayAchievements(List<PlayerAchievement> achievements)
        {
            // Make a box for it.
            const float greyTint = .8f;
            GUI.color = new Color(greyTint, greyTint, greyTint);
            GUI.Box(ContentRect, "");

            GUI.color = Color.white;

            // Bordered scroll view.
            //Debug.Log(_scrollViewRect + "\n" + _scrollDelta + "\n" + _contentRect);
            _scrollDelta = GUI.BeginScrollView(_scrollViewRect, _scrollDelta, _contentRect, false, true);

            // Bordered achievement area.         
            //GUI.BeginGroup(_contentRect);

            // Draw achievements.
            var dynamicRect = _contentRect;
            dynamicRect.height = ACHIEVEMENT_HEIGHT;
            foreach (var achievement in achievements)
            {
                DrawAchievement(achievement, dynamicRect);

                dynamicRect.y += ACHIEVEMENT_HEIGHT + ACHIEVEMENT_SPACE;
            }

            //GUI.EndGroup();

            GUI.EndScrollView();
        }

        private void DrawAchievement(PlayerAchievement achievement, Rect bounds)
        {
            // Achievement GUI label is coded as MiddleLeft anchored.
            GUI.skin.label.alignment = TextAnchor.MiddleLeft;
            GUI.enabled = achievement.HasUserUnlocked;

            const int bottomHeight = 10;

            // AsyncCache original values.
            var originalFontSize = GUI.skin.label.fontSize;
            var originalAlignment = GUI.skin.label.alignment;

            // Border.
            const float rgb = .1f;
            GUI.color = new Color(rgb, rgb, rgb);
            GUI.Box(bounds, "");

            // Image.
            var imageWidthHeight = bounds.height - ACHIEVEMENT_BORDER_X2 - ACHIEVEMENT_BORDER_X2 - ACHIEVEMENT_BORDER -
                                   bottomHeight;

            var imageRect = new Rect(bounds.x + ACHIEVEMENT_BORDER, bounds.y + ACHIEVEMENT_BORDER, imageWidthHeight,
                imageWidthHeight);
            GUI.color = Color.white;

            if (achievement.IconTexture == null)
                GUI.Box(imageRect, achievement.IconTexture);
            else
                GUI.DrawTexture(imageRect, achievement.IconTexture);

            // Title text.
            GUI.skin.label.normal.textColor = Color.white;
            GUI.skin.label.fontSize = 12;
            GUI.color = Color.white;
            const int titleHeight = 20;
            var titleOffset = imageWidthHeight + ACHIEVEMENT_BORDER_X2;
            var titleRect = new Rect(bounds.x + titleOffset, bounds.y + ACHIEVEMENT_BORDER,
                bounds.width - titleOffset - ACHIEVEMENT_BORDER, titleHeight);
            GUI.Label(titleRect, achievement.achievement);

            // Description text.
            //1.5.0
            //          GUI.skin.label.normal.textColor = achievement.HasUserUnlocked ? Color.grey : Color.white;
            GUI.skin.label.normal.textColor = Color.white;
            GUI.skin.label.fontSize = 10;
            var descriptionRect = titleRect;
            descriptionRect.height = 50;
            descriptionRect.y += titleHeight;
            GUI.Label(descriptionRect, achievement.description);

            // Difficulty color box.
            var achievementColor = AchievementColor(achievement.DifficultyValue);
            var difficultyDisplayRect = new Rect(bounds.x + ACHIEVEMENT_BORDER,
                imageRect.y + imageRect.height + ACHIEVEMENT_BORDER, imageRect.width, ACHIEVEMENT_BORDER);
            GUI.color = achievementColor;
            GUI.Box(difficultyDisplayRect, "");

            GUI.color = Color.white;

            // Bottom line.
            const float doubleBottomHeight = bottomHeight * 2f;
            var bottomRect = new Rect(bounds.x + ACHIEVEMENT_BORDER, bounds.y + (bounds.height - doubleBottomHeight),
                bounds.width - ACHIEVEMENT_BORDER_X2, doubleBottomHeight);
            GUI.skin.label.fontSize = 10;

            // Difficulty Text.
            GUI.skin.label.normal.textColor = achievementColor;

            GUI.Label(bottomRect, achievement.DifficultyValue.ToString());

            // Date achieved text.
            GUI.skin.label.normal.textColor = Color.white;
            GUI.skin.label.alignment = TextAnchor.MiddleRight;

            //          GUI.Label(bottomRect, ((achievement.HasUserUnlocked) ? "UNLOCKED" : "Created") + " on " + achievement.DateAchieved);
            GUI.Label(bottomRect, achievement.HasUserUnlocked ? "Unlocked" : "Locked");

            // Reset values.
            GUI.skin.label.fontSize = originalFontSize;
            GUI.skin.label.alignment = originalAlignment;
            GUI.skin.label.normal.textColor = Color.black;
        }

        private static Color AchievementColor(PlayerAchievement.Difficulty difficultyValue)
        {
            switch (difficultyValue)
            {
                case PlayerAchievement.Difficulty.Easy:
                    return Color.green;
                case PlayerAchievement.Difficulty.Medium:
                    return Color.yellow;
                case PlayerAchievement.Difficulty.Hard:
                    return Color.red;
                case PlayerAchievement.Difficulty.Unknown:
                    return Color.grey;
                default:
                    throw new InvalidOperationException("No color for Difficulty " + difficultyValue);
            }
        }

        public override void UpdateRects()
        {
            base.UpdateRects();

            // Set the scroll view to a smaller border.
            _scrollViewRect = ReduceByBorder(ContentRect, SMALL_BORDER);

            // Set the content to the same size. 
            // Except make it thinner and longer, to match the number of achievements.
            _contentRect = _scrollViewRect;
            _contentRect.width -= 20;
            _contentRect.height = Mathf.Max(
                Idnet.User.Current.Achievements.Count * (ACHIEVEMENT_HEIGHT + ACHIEVEMENT_SPACE),
                _scrollViewRect.height);
        }

        private Rect ReduceByBorder(Rect startingRect, float border)
        {
            var borderDoubled = border * 2;
            return new Rect(startingRect.x + border,
                startingRect.y + border,
                startingRect.width - borderDoubled,
                startingRect.height - borderDoubled);
        }

        public void AchievementListUpdated(List<PlayerAchievement> achievements)
        {
            _achievements = achievements;
            var UnlockedAchievementsCount = 0;
            foreach (var achievement in _achievements)
            {
                achievement.AsyncCache(Gui);
                UnlockedAchievementsCount = achievement.HasUserUnlocked
                    ? UnlockedAchievementsCount + 1
                    : UnlockedAchievementsCount;
            }

            UpdateRects();

            Gui.StatusTextColor = Color.grey;

            if (achievements.Count > 0)
            {
                if (UnlockedAchievementsCount == 0)
                {
                    Gui.StatusText = "No Achievements unlocked. ";
                }
                else if (UnlockedAchievementsCount == 1)
                {
                    Gui.StatusText = "Congratulations! You have unlocked " + UnlockedAchievementsCount +
                                     " achievement.";
                }
                else
                {
                    Gui.StatusText = "Congratulations! You have unlocked " + UnlockedAchievementsCount +
                                     " achievements.";
                }

                //1.5.0
                if (!Idnet.User.LoggedIn())
                {
                    Gui.StatusText = "";
                }
            }
            else
            {
                Gui.StatusText = "The developer has not set up any achievements.";
            }
        }
    }

    /// <summary>
    ///     Shows all the users achievements.
    /// </summary>
    public class ListUserLevelsState : GuiState
    {
        private int _pageIndex;

        public ListUserLevelsState(IdnetGui gui)
            : base(gui)
        {
        }

        public override string Title
        {
            get { return "User Levels"; }
        }

        protected override void Enter()
        {
            Gui.StatusTextColor = Color.grey;
            Gui.StatusText = "Loading worldwide user maps...";
            _pageIndex = 0;
        }

        protected override void CustomGui()
        {
            ListUserLevels(Idnet.User.Current.Achievements, _pageIndex);
        }

        /// <summary>
        ///     Display the user maps.
        /// </summary>
        /// <param name="achievements"></param>
        /// <param name="startIndex"></param>
        private void ListUserLevels(List<PlayerAchievement> achievements, int startIndex)
        {
        }
    }

    /// <summary>
    ///     Empty state. Disables the GUI.
    /// </summary>
    public class ClosedState : GuiState
    {
        public ClosedState(IdnetGui gui)
            : base(gui)
        {
        }

        public override string Title
        {
            get { return ""; }
        }

        protected override void Enter()
        {
            Gui.useGUILayout = false;


            Idnet.I.CloseGui();
        }

        protected override void Exit()
        {
            Gui.useGUILayout = true;
        }

        protected override void CustomGui()
        {
        }
    }

    /// <summary>
    ///     Will close the GUI after a small amount of time.
    ///     Think of it as a transition state.
    /// </summary>
    public class ClosingState : GuiState
    {
        public ClosingState(IdnetGui gui)
            : base(gui)
        {
        }

        public override string Title
        {
            get { return "Idnet"; }
        }

        protected override void Enter()
        {
            Gui.StatusText += ". Closing";
            Gui.Interactable = true;

            Gui.StartCoroutine(CR_MoveToClosedState());
        }

        private IEnumerator CR_MoveToClosedState()
        {
            for (var i = 0; i < 3; i++)
            {
                yield return new WaitForSeconds(.1f);
                Gui.StatusText += ".";
            }

            Gui.Cfsm.SetState<ClosedState>();
        }

        protected override void CustomGui()
        {
        }
    }

    /// <summary>
    ///     Base class for all GUI states.
    ///     Includes GUI used by all states.
    /// </summary>
    public abstract class GuiState : State
    {
        public const float GUI_WIDTH = 400;
        public const float GUI_HEIGHT = 400;
        public const float GUI_WIDTH_SmallRect = 350;
        public const float GUI_HEIGHT_SmallRect = 270;
        public const float CLOSE_BUTTON_WIDTH_HEIGHT = 25;
        public const float STATUS_TEXT_END_OFFSET = 65;

        public static Vector2 ScreenCenter;
        protected readonly IdnetGui Gui;


        protected GuiState(IdnetGui gui)
        {
            Gui = gui;
        }

        /// <summary>
        ///     Rect for the Idnet box.
        /// </summary>
        public static Rect BoxRect { get; private set; }

        /// <summary>
        ///     Lines Rect.
        /// </summary>
        public static Rect LineRect { get; private set; }


        /// <summary>
        ///     Rect for the specific window content.
        /// </summary>
        public static Rect ContentRect { get; private set; }

        public abstract string Title { get; }


        /// <summary>
        ///     Updates the middle point of the screen.
        ///     Call whenever orientation changes.
        /// </summary>
        public static bool RefreshScreenCenter()
        {
            // These values have put off the entire GUI.
            var newScreenCenter = new Vector2(Screen.width * .5f - 95, Screen.height * .5f - 3);

            if (newScreenCenter == ScreenCenter) return false;

            ScreenCenter = newScreenCenter;

            return true;
        }

        /// <summary>
        ///     Draw the Email, (optionally) Nickname and Password fields.
        /// </summary>
        /// <param name="includeNicknameField">Do we include nickname field?</param>
        /// <param name="readOnly">Cannot modify.</param>
        protected Rect EmailNicknamePasswordFields(int yOffset = 54, bool includeNicknameField = false,
            bool readOnly = false)
        {
            GUI.enabled = Gui.Interactable;

            GUI.skin.label.alignment = TextAnchor.MiddleLeft;

            GUI.skin.label.fontSize = 15;
            const float textHeight = 30;
            const float shortenText = 5;
            const float lengthenGap = 10;
            var dynamicRect = new Rect(ContentRect.x, ContentRect.y, ContentRect.width, textHeight);

            //line
            GUI.DrawTexture(
                new Rect(ScreenCenter.x - 51, ScreenCenter.y - yOffset - 36, GUI_WIDTH_SmallRect / 1.2f, 1.4f),
                Gui.GreyPixel);

            GUI.Label(new Rect(ScreenCenter.x - 44, ScreenCenter.y - yOffset, 95, 22), "Email");

            dynamicRect.y += textHeight - shortenText;
            var emailValue = GUI.TextField(new Rect(ScreenCenter.x + 43, ScreenCenter.y - yOffset - 3, 190, 28),
                Idnet.User.Current.Email);

            if (!readOnly)
                Idnet.User.Current.Email = emailValue;
            yOffset -= 40;
            dynamicRect.y += textHeight + lengthenGap;

            if (includeNicknameField)
            {
                GUI.Label(new Rect(ScreenCenter.x - 44, ScreenCenter.y - yOffset, 95, 22), "Nickname");
                dynamicRect.y += textHeight - shortenText;
                var nickNameValue = GUI.TextField(new Rect(ScreenCenter.x + 43, ScreenCenter.y - yOffset - 3, 190, 28),
                    Idnet.User.Current.Nickname);

                dynamicRect.y += textHeight + lengthenGap;
                if (!readOnly)
                    Idnet.User.Current.Nickname = nickNameValue;
                yOffset -= 40;

                //line
                GUI.DrawTexture(
                    new Rect(ScreenCenter.x - 51, ScreenCenter.y - yOffset + 74, GUI_WIDTH_SmallRect / 1.2f, 1.4f),
                    Gui.GreyPixel);
            }

            // Passwords do not get shown in readOnly.
            if (!readOnly)
            {
                GUI.Label(new Rect(ScreenCenter.x - 44, ScreenCenter.y - yOffset, 95, 22), "Password");
                dynamicRect.y += textHeight - shortenText;
                Gui.PasswordField =
                    GUI.PasswordField(new Rect(ScreenCenter.x + 43, ScreenCenter.y - yOffset - 3, 190, 28),
                        Gui.PasswordField, '*');

                if (!includeNicknameField)
                    //line
                    GUI.DrawTexture(
                        new Rect(ScreenCenter.x - 51, ScreenCenter.y - yOffset + 110, GUI_WIDTH_SmallRect / 1.2f, 1.4f),
                        Gui.GreyPixel);
            }

            dynamicRect.y += textHeight + lengthenGap + 15;


            GUI.skin.label.fontSize = 0;

            return dynamicRect;
        }


        public void ShowGui()
        {
            if ((Idnet.I.Gui.Cfsm.ActiveType == typeof(IdnetGui.LoginState) ||
                 Idnet.I.Gui.Cfsm.ActiveType == typeof(IdnetGui.RegisterState)))
            {
                CustomGui();
                return;
            }

            // Default GUI.

            // Skin.
            GUI.skin = Gui.Skin;
            GUI.skin.font = Gui.Font;
            GUI.skin.settings.cursorColor = Color.black;
            GUI.color = Color.white;

            // White box && title.
            GUI.Box(BoxRect, Title);

            GUI.enabled = Gui.Interactable;

            CustomGui(); // <<< Custom.

            GUI.color = Color.white;
            GUI.enabled = true;

            // It's safe to assume whenever we cannot interact, we are loading something.
            if (!Gui.Interactable)
            {
                GUI.DrawTexture(new Rect(ScreenCenter.x + 70, ScreenCenter.y - 0, 60, 60), Gui.LoadingImage);
            }

            // Status text.
            const float statusTextBorder = 41;
            const float statusTextYOffset = 6;
            GUI.TextArea(new Rect(BoxRect.x,
                    BoxRect.y + statusTextBorder + statusTextYOffset,
                    BoxRect.width,
                    STATUS_TEXT_END_OFFSET - statusTextYOffset),
                Gui.StatusText, Gui.responseStyle);

            float closeButtonBorder;
            var logoBorder = 0.0f;
            //If Leaderboard window,then logo and close button have different position.
            if (Gui.Cfsm.ActiveType == typeof(LeaderboardState))
            {
                closeButtonBorder = 14.0f;
                logoBorder = 21.0f / 2;
            }
            else
            {
                closeButtonBorder = 3.0f;
                logoBorder = 6.0f / 2;
            }

            // Close button label.
            if (GUI.Button(new Rect(
                    BoxRect.x + (BoxRect.width - CLOSE_BUTTON_WIDTH_HEIGHT - closeButtonBorder),
                    BoxRect.y + closeButtonBorder + CLOSE_BUTTON_WIDTH_HEIGHT / 2.7f,
                    CLOSE_BUTTON_WIDTH_HEIGHT,
                    CLOSE_BUTTON_WIDTH_HEIGHT),
                Gui.CloseButtonTexture,
                GUIStyle.none))
            {
                Idnet.I.CloseGui();
                Idnet.I.TimerLeaderboard = false;
                Idnet.I.ReverseLeaderboard = false;
            }

            // disable y8account logo when showing achievements
            if (Gui.Cfsm.ActiveType != typeof(ListAchievementsState))
            {
                //Open idnet link in new tab GUI workaround.
                var E = Event.current;
                var R = new Rect(
                    BoxRect.x + (BoxRect.width - Gui.Y8AccountLogo.width / 2 - logoBorder),
                    BoxRect.y + (BoxRect.height - Gui.Y8AccountLogo.height / 2 - logoBorder),
                    Gui.Y8AccountLogo.width / 2,
                    Gui.Y8AccountLogo.height / 2);
                if (E.type == EventType.MouseDown && R.Contains(E.mousePosition))
                {
#if UNITY_WEBGL
                    var url = "https://account.y8.com";
                    Idnet.I.OpenLink(url);
#else
                    Application.OpenURL("https://account.y8.com");
#endif

                }

                // Logo.
                GUI.Button(new Rect(
                        BoxRect.x + (BoxRect.width - Gui.Y8AccountLogo.width / 2 - logoBorder),
                        BoxRect.y + (BoxRect.height - Gui.Y8AccountLogo.height / 2 - logoBorder),
                        Gui.Y8AccountLogo.width / 2,
                        Gui.Y8AccountLogo.height / 2),
                    Gui.Y8AccountLogo,
                    Gui.linkStyle);
            }
        }

        protected override void Update()
        {
            if (RefreshScreenCenter())
            {
                UpdateRects();
                UpdateSmallRects();
            }
        }

        protected abstract void CustomGui();

        public virtual void UpdateRects()
        {
            if (Gui.Cfsm.ActiveType == typeof(LeaderboardState))
            {
                //a bit more padding for leaderboard big boxrect label(more text padding from top of white box)
                Gui.Skin.box.padding = new RectOffset(5, 5, 20, 5);
            }
            else
            {
                //a bit less padding for achievement big boxrect label(less text padding from top of white box)
                Gui.Skin.box.padding = new RectOffset(5, 5, 10, 5);
            }

            BoxRect = new Rect(ScreenCenter.x - 101, ScreenCenter.y - 194, GUI_WIDTH, GUI_HEIGHT);

            ContentRect = new Rect(
                BoxRect.x + 10,
                BoxRect.y + STATUS_TEXT_END_OFFSET + 10,
                BoxRect.width - 20,
                BoxRect.height - STATUS_TEXT_END_OFFSET - 35);
        }

        public virtual void UpdateSmallRects()
        {
            //a bit less padding for small boxrect label(less text padding from top of white box)
            Gui.Skin.box.padding = new RectOffset(5, 5, 10, 5);

            BoxRect = new Rect(ScreenCenter.x - 80, ScreenCenter.y - 131, GUI_WIDTH_SmallRect, GUI_HEIGHT_SmallRect);

            ContentRect = new Rect(
                BoxRect.x + 10,
                BoxRect.y + STATUS_TEXT_END_OFFSET + 10,
                BoxRect.width - 20,
                BoxRect.height - STATUS_TEXT_END_OFFSET - 35);
        }
    }

    // ReSharper disable InconsistentNaming
    public GUIStyle loginButStyle;

    public GUIStyle registerButStyle;
    public GUIStyle linkStyle;
    public GUIStyle responseStyle;
    public GUIStyle leaderboardeStyle;
    public GUIStyle leaderboardelinkStyle;

    public GUIStyle modeButtonStyle;
    // ReSharper restore InconsistentNaming
}