﻿using AsmodeeDigital.Common.Plugin.Utils.Extensions;
using AsmodeeDigital.PlayReal.Plugin.Domain.GameState;
using AsmodeeDigital.PlayReal.Plugin.Domain.Players;
using AsmodeeDigital.PlayReal.Plugin.Manager;
using AsmodeeDigital.PlayReal.Samples.Domain.GameState.Events;
using AsmodeeDigital.PlayReal.Samples.Logic;
using AsmodeeDigital.PlayReal.Samples.UI;
using AsmodeeDigital.PlayReal.Samples.UI.LobbyGame;
using com.daysofwonder;
using com.daysofwonder.async;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

namespace AsmodeeDigital.PlayReal.Samples.Views
{
    /// <summary>
    /// View displayed to create a game and invite friends
    /// </summary>
    public class LobbyGameView : MonoBehaviour
    {
        /// <summary>
        /// UI references of LobbyGameView
        /// </summary>
        [Serializable]
        public class UI
        {
            public Canvas Canvas;

            [Header("Panels")]
            public Transform CreateGamePanel;
            public Transform JoinGamePanel;
            public Transform ResumeGamePanel;
            public Transform LocalGamePanel;
            public Transform ReplayGamePanel;

            [Header("Tabs")]
            public Toggle LocalToggle;
            public Toggle JoinToggle;
            public Toggle QuickToggle;
            public Toggle AdvancedToggle;
            public Toggle InvitationToggle;


            [Header("Replay")]
            public ToggleGroup ReplayGameItemsParent;
            public Button ReplayGameButton;
            public Dictionary<long, ReplayGameItem> ReplayGameItems = new Dictionary<long, ReplayGameItem>();

            [Header("Create offline game")]
            public List<LobbyPlayerSlot> LobbyPlayerSlots;
            public Button CreateOfflineGameButton;

            [Header("Opened games")]
            public List<GameItem> OpenedGameItems;
            public ToggleGroup OpenedGameItemsParent;
            public Text SelectedOpenedGameDetails;
            public Button OpenedGameJoinButton;
            public InputField OpenedGamePasswordInputField;
            public Transform OpenedGamePasswordFrame;

            [Header("Resume games")]
            public List<GameItem> ResumeGameItems;
            public ToggleGroup ResumeGameItemsParent;
            public Text SelectedResumeGameDetails;
            public Button ResumeGameJoinButton;

            [Header("Create online game")]
            public Transform InvitationPlayerSlots;
            public List<LobbyPlayerSlot> InvitationLobbyPlayerSlots;
            public Transform CountPlayersSlot;
            public Transform FirstPlayerSlot;
            public Transform MinimumKarmaSlot;
            public Transform MinimumScoreSlot;
            public Transform PrivateSlot;
            public Transform RankedSlot;
            public Transform DurationSlot;
            public Transform ReplaceByBotSlot;
            public Dropdown CountPlayersDropdown;
            public Dropdown FirstPlayerDropdown;
            public Dropdown MinimumKarmaDropdown;
            public Dropdown MinimumScoreDropdown;
            public Toggle PrivateToggle;
            public InputField PrivatePasswordText;
            public Toggle RankedToggle;
            public Dropdown DurationDropdown;
            public Toggle ReplaceByBotToggle;
            public Button CreateOnlineGameButton;

            [Header("Other")]
            public PopupWaitingGame PopupWaitingGame;
        }

        /// <summary>
        /// UI instance
        /// </summary>
        public UI ui;

        [Header("Prefab")]
        public GameItem GameItemPrefab;
        public ReplayGameItem ReplayGameItemPrefab;

        /// <summary>
        /// Logic of the view
        /// </summary>
        private LobbyGameLogic _lobbyGameLogic;

        public static bool IsDestroyed = false;

        private void Start()
        {
            Init();
        }

        private void Update()
        {
            if (Input.GetKeyDown(KeyCode.Escape))
                _lobbyGameLogic.ShowMainMenu();
        }

        /// <summary>
        /// Initialize the view - Creating logic - Creating .Net events
        /// </summary>
        private void Init()
        {
            IsDestroyed = false;

            _lobbyGameLogic = new LobbyGameLogic(PlayRealManager.Instance.ServerConnection, PlayRealManager.Instance.Persistence);
            _lobbyGameLogic.LogEnabled = PlayRealManager.Instance.LogLogicEnabled;

            _lobbyGameLogic.LobbyOpenGameListEvent += LobbyGameLogic_LobbyOpenGameListEvent;
            _lobbyGameLogic.LobbyResumeGameListEvent += LobbyGameLogic_LobbyResumeGameListEvent;

            _lobbyGameLogic.InvitationArrivedEvent += LobbyGameLogic_InvitationArrivedEvent;
            _lobbyGameLogic.InvitationAcceptedEvent += LobbyGameLogic_InvitationAcceptedEvent;
            _lobbyGameLogic.InvitationRejectedEvent += LobbyGameLogic_InvitationRejectedEvent;
            _lobbyGameLogic.LobbyNewPlayerEvent += LobbyGameLogic_LobbyNewPlayerEvent;
            _lobbyGameLogic.LobbyPlayerLeftGameEvent += LobbyGameLogic_LobbyPlayerLeftGameEvent;
            _lobbyGameLogic.LobbyJoinDeniedEvent += LobbyGameLogic_LobbyJoinDeniedEvent;

            _lobbyGameLogic.Init();
        }

        /// <summary>
        /// Refresh the open games list or the active games list depending on parameters
        /// </summary>
        /// <param name="listGameDetails">List of games to show</param>
        /// <param name="parentToggle">Parent toggle</param>
        /// <param name="gameItems">Game items</param>
        /// <param name="joinButton">Join button</param>
        /// <param name="details">Text details</param>
        private void RefreshGameList(List<IGameDetails> listGameDetails, ToggleGroup parentToggle, List<GameItem> gameItems, Button joinButton, Text details)
        {
            if (IsDestroyed)
                return;

            gameItems.ForEach(gi => gi.Refreshed = false);

            foreach (IGameDetails gameDetails in listGameDetails)
            {
                RefreshGameItem(gameDetails, parentToggle, gameItems);
            }

            gameItems.FindAll(gi => !gi.Refreshed).ForEach(gi =>
            {
                gi.ui.Toggle.isOn = false;
                gi.gameObject.SetActive(false);
            });

            if (parentToggle.AnyTogglesOn())
            {
                joinButton.interactable = true;
            }
            else
            {
                joinButton.interactable = false;
                details.text = string.Empty;
            }
        }

        /// <summary>
        /// Refresh game status on UI
        /// </summary>
        /// <param name="statusReport"></param>
        private void RefreshGameItem(IGameDetails gameDetails, ToggleGroup parent, List<GameItem> gameItems)
        {
            //---> Search the existing game item
            GameItem gameItem = gameItems.Find(g => g.GameDetails.game_id == gameDetails.game_id);

            //---> If not exist recycle from the pool
            if (gameItem == null)
                gameItem = gameItems.Find(g => !g.gameObject.activeSelf);

            if (gameItem == null)
            {
                gameItem = Instantiate<GameItem>(GameItemPrefab);
                gameItem.ui.Toggle.group = parent;
                gameItem.ui.Toggle.onValueChanged.AddListener(GameItemToggle_OnChanged);

                gameItem.transform.SetParent(parent.transform);
                gameItem.transform.localScale = Vector3.one;

                gameItems.Add(gameItem);
            }

            StatusReport statusReport = gameDetails as StatusReport;

            gameItem.gameObject.SetActive(true);
            gameItem.Refreshed = true;
            gameItem.ui.GameName.text = gameDetails.configuration.name;
            gameItem.GameDetails = gameDetails;

            if (statusReport != null)
            {
                if (statusReport.status == GameStatus.IN_PROGRESS)
                {
                    Player playerTurn = statusReport.players.Find(p => p.id == statusReport.next_player_ids.First());

                    if (playerTurn.w_w_w_id == PlayRealManager.Instance.Persistence.ConnectedPlayer.w_w_w_id)
                        gameItem.ui.Detail.text = "Your turn";
                    else
                        gameItem.ui.Detail.text = String.Format("{0}'s turn", playerTurn.name);
                }
                else
                {
                    gameItem.ui.Detail.text = statusReport.status.ToString();
                }

                gameItem.ui.Toggle.gameObject.SetActive(statusReport.status == GameStatus.IN_PROGRESS);
            }
            else
            {
                TimeSpan timeSpan = TimeSpan.FromSeconds(gameDetails.configuration.timeout);
                gameItem.ui.Detail.text = string.Format("{0} / player", timeSpan.ToStringExtended(""));
            }
        }

        #region UI interactions
        /// <summary>
        /// Show a panel and hide the others
        /// </summary>
        /// <param name="panel">Panel to show</param>
        private void ShowPanel(Transform panel)
        {
            ui.LocalGamePanel.gameObject.SetActive(panel == ui.LocalGamePanel);
            ui.ReplayGamePanel.gameObject.SetActive(panel == ui.ReplayGamePanel);
            ui.JoinGamePanel.gameObject.SetActive(panel == ui.JoinGamePanel);
            ui.CreateGamePanel.gameObject.SetActive(panel == ui.CreateGamePanel);
            ui.ResumeGamePanel.gameObject.SetActive(panel == ui.ResumeGamePanel);
        }

        /// <summary>
        /// Show [ONLINE] tab
        /// </summary>
        /// <param name="isOn"></param>
        public void ShowOnlineTab(bool isOn)
        {
            if (!isOn)
                return;

            ShowPanel(ui.JoinGamePanel);

            ui.JoinToggle.isOn = true;
        }

        /// <summary>
        /// Show [LOCAL] tab
        /// </summary>
        /// <param name="isOn"></param>
        public void ShowLocalTab(bool isOn)
        {
            if (!isOn)
                return;

            ShowPanel(ui.LocalGamePanel);

            ui.LobbyPlayerSlots[0].SetCurrentPlayerInSlot();
            ui.LobbyPlayerSlots[1].SetEmptySlot();
            ui.LobbyPlayerSlots[2].HideSlot();
            ui.LobbyPlayerSlots[0].transform.SetSiblingIndex(0);
            ui.LobbyPlayerSlots[1].transform.SetSiblingIndex(1);
            ui.LobbyPlayerSlots[2].transform.SetSiblingIndex(2);
        }

        /// <summary>
        /// Show [REPLAY] tab
        /// </summary>
        /// <param name="isOn"></param>
        public void ShowReplayTab(bool isOn)
        {
            if (!isOn)
                return;

            ShowPanel(ui.ReplayGamePanel);

            //---> Retrieve all replay
            List<GameStateBase> gameStatesReplay = _lobbyGameLogic.GetReplayGameState();

            //---> Instantiate replay game item
            foreach (GameStateBase gameStateReplay in gameStatesReplay)
            {
                GameInitialized gameInit = (GameInitialized)gameStateReplay.Events.Find(e => e is GameInitialized);

                if (!ui.ReplayGameItems.ContainsKey(gameInit.Time))
                {
                    ReplayGameItem replayGameItem = Instantiate<ReplayGameItem>(ReplayGameItemPrefab);
                    replayGameItem.ui.Toggle.group = ui.ReplayGameItemsParent;
                    replayGameItem.ui.Toggle.onValueChanged.AddListener(ReplayGameItemToggle_OnChanged);
                    replayGameItem.GameState = gameStateReplay;

                    replayGameItem.ui.Date.text = new DateTime(gameInit.Time).ToString("dd/MM/yyy - HH:mm");
                    for (int i = 0; i < gameStateReplay.PlayerSeats.Count; i++)
                    {
                        replayGameItem.ui.Players.text += gameStateReplay.PlayerSeats[i].Name + (i < gameStateReplay.PlayerSeats.Count - 1 ? " - " : "");
                    }

                    replayGameItem.transform.SetParent(ui.ReplayGameItemsParent.transform);
                    replayGameItem.transform.localScale = Vector3.one;

                    ui.ReplayGameItems.Add(gameInit.Time, replayGameItem);
                }
            }
        }

        /// <summary>
        /// Show [JOIN] tab
        /// </summary>
        /// <param name="isOn"></param>
        public void ShowJoinTab(bool isOn)
        {
            if (!isOn)
                return;

            ShowPanel(ui.JoinGamePanel);

            _lobbyGameLogic.WhatsNewPussycat();
        }

        /// <summary>
        /// Show [CREATE] tab
        /// </summary>
        /// <param name="isOn"></param>
        public void ShowCreateTab(bool isOn)
        {
            if (!isOn)
                return;

            ShowPanel(ui.CreateGamePanel);

            ui.QuickToggle.isOn = true;
        }

        /// <summary>
        /// Show [RESUME] tab
        /// </summary>
        /// <param name="isOn"></param>
        public void ShowResumeTab(bool isOn)
        {
            if (!isOn)
                return;

            ShowPanel(ui.ResumeGamePanel);
        }

        /// <summary>
        /// Show [QUICK] tab
        /// </summary>
        /// <param name="isOn"></param>
        public void ShowQuickTab(bool isOn)
        {
            if (!isOn)
                return;

            ShowPanel(ui.CreateGamePanel);

            ui.InvitationPlayerSlots.gameObject.SetActive(false);
            ui.CountPlayersSlot.gameObject.SetActive(true);
            ui.FirstPlayerSlot.gameObject.SetActive(false);
            ui.MinimumKarmaSlot.gameObject.SetActive(false);
            ui.MinimumScoreSlot.gameObject.SetActive(false);
            ui.PrivateSlot.gameObject.SetActive(false);
            ui.RankedSlot.gameObject.SetActive(true);
            ui.DurationSlot.gameObject.SetActive(false);
            ui.ReplaceByBotSlot.gameObject.SetActive(false);

            ui.CreateOnlineGameButton.interactable = true;
        }

        /// <summary>
        /// Show [ADVANCED] tab
        /// </summary>
        /// <param name="isOn"></param>
        public void ShowAdvancedTab(bool isOn)
        {
            if (!isOn)
                return;

            ShowPanel(ui.CreateGamePanel);

            ui.InvitationPlayerSlots.gameObject.SetActive(false);
            ui.CountPlayersSlot.gameObject.SetActive(true);
            ui.FirstPlayerSlot.gameObject.SetActive(true);
            ui.MinimumKarmaSlot.gameObject.SetActive(true);
            ui.MinimumScoreSlot.gameObject.SetActive(true);
            ui.PrivateSlot.gameObject.SetActive(true);
            ui.RankedSlot.gameObject.SetActive(true);
            ui.DurationSlot.gameObject.SetActive(true);
            ui.ReplaceByBotSlot.gameObject.SetActive(true);

            ui.CreateOnlineGameButton.interactable = true;
        }

        /// <summary>
        /// Show [INVITATION] tab
        /// </summary>
        /// <param name="isOn"></param>
        public void ShowInvitationTab(bool isOn)
        {
            if (!isOn)
                return;

            ShowPanel(ui.CreateGamePanel);

            ui.InvitationPlayerSlots.gameObject.SetActive(true);
            ui.CountPlayersSlot.gameObject.SetActive(false);
            ui.FirstPlayerSlot.gameObject.SetActive(false);
            ui.MinimumKarmaSlot.gameObject.SetActive(false);
            ui.MinimumScoreSlot.gameObject.SetActive(false);
            ui.PrivateSlot.gameObject.SetActive(false);
            ui.RankedSlot.gameObject.SetActive(true);
            ui.DurationSlot.gameObject.SetActive(true);
            ui.ReplaceByBotSlot.gameObject.SetActive(false);

            ui.InvitationLobbyPlayerSlots[0].SetCurrentPlayerInSlot();
            ui.InvitationLobbyPlayerSlots[1].SetEmptySlot();
            ui.InvitationLobbyPlayerSlots[2].HideSlot();
            ui.InvitationLobbyPlayerSlots[0].transform.SetSiblingIndex(0);
            ui.InvitationLobbyPlayerSlots[1].transform.SetSiblingIndex(1);
            ui.InvitationLobbyPlayerSlots[2].transform.SetSiblingIndex(2);

            ui.CreateOnlineGameButton.interactable = false;

            //---> Select the [FRIENDS] tab when the [INVITATION] tab is selected
            LobbyPlayersView.Instance.SelectFriendsTab();
        }

        /// <summary>
        /// Event raised when a player is deleted from a slot
        /// </summary>
        /// <param name="lobbyPlayerSlots"></param>
        /// <param name="dropSlot"></param>
        /// <param name="createGameButton"></param>
        private void OnDraggableDeleted(List<LobbyPlayerSlot> lobbyPlayerSlots, DropSlot dropSlot, Button createGameButton)
        {
            LobbyPlayerSlot lobbyPlayerSlot = lobbyPlayerSlots.Find(lps => lps.ui.Slot == dropSlot);
            lobbyPlayerSlot.HideSlot();

            lobbyPlayerSlots.FindAll(lps => lps.State == LobbyPlayerSlotState.Empty).ForEach(lps => lps.HideSlot());

            LobbyPlayerSlot lobbyPlayerSlotInactive = lobbyPlayerSlots.Find(lps => lps.State == LobbyPlayerSlotState.Hidden);

            lobbyPlayerSlotInactive.SetEmptySlot();

            //---> [Create game] button is active if at least one player is invited
            createGameButton.interactable = lobbyPlayerSlots.Exists(lps => lps.IsInvited());
        }

        /// <summary>
        /// Event raised when a player is added to a slot
        /// </summary>
        /// <param name="lobbyPlayerSlots"></param>
        /// <param name="dropSlot"></param>
        /// <param name="createGameButton"></param>
        private void OnDraggableAdded(List<LobbyPlayerSlot> lobbyPlayerSlots, DropSlot dropSlot, Button createGameButton)
        {
            LobbyPlayerSlot lobbyPlayerSlot = lobbyPlayerSlots.Find(lps => lps.ui.Slot == dropSlot);
            lobbyPlayerSlot.SetPlayerFromDraggable();

            LobbyPlayerSlot lobbyPlayerSlotInactive = lobbyPlayerSlots.Find(lps => lps.State == LobbyPlayerSlotState.Hidden);

            if (lobbyPlayerSlotInactive != null)
            {
                lobbyPlayerSlotInactive.transform.SetAsLastSibling();
                lobbyPlayerSlotInactive.SetEmptySlot();
            }

            createGameButton.interactable = true;
        }

        /// <summary>
        /// Event raised when a player is deleted from a local game slot
        /// </summary>
        /// <param name="dropSlot"></param>
        public void LocalPanel_OnDraggableDeleted(DropSlot dropSlot)
        {
            OnDraggableDeleted(ui.LobbyPlayerSlots, dropSlot, ui.CreateOfflineGameButton);
        }

        /// <summary>
        /// Event raised when a player is added to a local game slot
        /// </summary>
        /// <param name="dropSlot"></param>
        public void LocalPanel_OnDraggableAdded(DropSlot dropSlot)
        {
            OnDraggableAdded(ui.LobbyPlayerSlots, dropSlot, ui.CreateOfflineGameButton);
        }

        /// <summary>
        /// Event raised when a player is deleted from an invitation game slot
        /// </summary>
        /// <param name="dropSlot"></param>
        public void InvitationPanel_OnDraggableDeleted(DropSlot dropSlot)
        {
            OnDraggableDeleted(ui.InvitationLobbyPlayerSlots, dropSlot, ui.CreateOnlineGameButton);
        }

        /// <summary>
        /// Event raised when a player is added to an invitation game slot
        /// </summary>
        /// <param name="dropSlot"></param>
        public void InvitationPanel_OnDraggableAdded(DropSlot dropSlot)
        {
            //---> If friend is already invited in the game, then the draggable icon is deleted
            if (ui.InvitationLobbyPlayerSlots.Exists(lps => lps.ui.Slot.CurrentDraggable != null && lps.ui.Slot.CurrentDraggable.Data == dropSlot.CurrentDraggable.Data && lps.ui.Slot != dropSlot))
            {
                LobbyPlayerSlot lobbyPlayerSlot = ui.InvitationLobbyPlayerSlots.Find(lps => lps.ui.Slot == dropSlot);
                lobbyPlayerSlot.SetEmptySlot();
                GameObject.Destroy(dropSlot.CurrentDraggable.gameObject);
            }
            else
            {
                OnDraggableAdded(ui.InvitationLobbyPlayerSlots, dropSlot, ui.CreateOnlineGameButton);
            }
        }

        /// <summary>
        /// Event raised when the password checkbox is toggled
        /// </summary>
        /// <param name="value"></param>
        public void Private_OnChanged(bool value)
        {
            ui.PrivatePasswordText.interactable = value;
            ui.PrivatePasswordText.readOnly = !value;
        }

        /// <summary>
        /// Event raised when the numbler of lpayer in the dropdownlist is changed.
        /// Change the FirstPlayerDropdown values
        /// </summary>
        /// <param name="selectedIndex"></param>
        public void NumberOfPlayer_OnChanged(int selectedIndex)
        {
            ui.FirstPlayerDropdown.ClearOptions();
            for (int i = 1; i < selectedIndex + 3; i++)
            {
                ui.FirstPlayerDropdown.options.Add(new Dropdown.OptionData(i.ToString()));
            }
            ui.FirstPlayerDropdown.value = 0;
            ui.FirstPlayerDropdown.RefreshShownValue();
        }

        /// <summary>
        /// Event raised when a GameItem is toggled (in the [JOIN] or [RESUME] tab)
        /// </summary>
        /// <param name="isOn"></param>
        private void GameItemToggle_OnChanged(bool isOn)
        {
            if (!isOn)
                return;

            GameItem gameItem = null;
            Text gameDetails = null;
            Button joinButton = null;

            if (ui.JoinToggle.isOn)
            {
                gameItem = ui.OpenedGameItems.Find(gi => gi.ui.Toggle.isOn);
                gameDetails = ui.SelectedOpenedGameDetails;
                joinButton = ui.OpenedGameJoinButton;
            }
            else
            {
                gameItem = ui.ResumeGameItems.Find(gi => gi.ui.Toggle.isOn);
                gameDetails = ui.SelectedResumeGameDetails;
                joinButton = ui.ResumeGameJoinButton;
            }

            string detail = String.Empty;

            if (gameItem != null)
            {
                foreach (IPlayer player in gameItem.GameDetails.players)
                {
                    if (detail != string.Empty)
                        detail += "\r\n";

                    detail += player.name;
                }

                joinButton.interactable = true;

                ui.OpenedGamePasswordInputField.text = string.Empty;
                ui.OpenedGamePasswordFrame.gameObject.SetActive(gameItem.GameDetails.configuration.@private);
            }
            else
            {
                joinButton.interactable = false;
                ui.OpenedGamePasswordFrame.gameObject.SetActive(false);
            }

            gameDetails.text = detail;
        }

        /// <summary>
        /// Event raised when a ReplayGameItem is toggled in the [REPLAY] tab
        /// </summary>
        /// <param name="isOn"></param>
        private void ReplayGameItemToggle_OnChanged(bool isOn)
        {
            if (!isOn)
                return;

            ReplayGameItem replayGameItem = ui.ReplayGameItems.Values.ToList().Find(rgi => rgi.ui.Toggle.isOn);

            ui.ReplayGameButton.interactable = replayGameItem != null;
        }

        /// <summary>
        /// Create a local, quick, advanced or invitation game depending on the tab selected
        /// </summary>
        public void CreateGame()
        {
            if (ui.LocalToggle.isOn)
            {
                List<IPlayerSeat> playerSeats = ui.LobbyPlayerSlots.ConvertAll<IPlayerSeat>(lps => lps.GetPlayerSeat());
                playerSeats.RemoveAll(lps => lps == null);

                //--- Re arrange player seats for the first player
                int indexFirstPlayer = ui.LobbyPlayerSlots.FindIndex(lps => lps.ui.FirstPlayer.isOn);
                if (indexFirstPlayer >= 0)
                {
                    List<IPlayerSeat> playerSeatsOrdered = new List<IPlayerSeat>();

                    for (int i = indexFirstPlayer; i < playerSeats.Count; i++)
                    {
                        IPlayerSeat playerSeat = playerSeats[i];
                        playerSeatsOrdered.Add(playerSeat);
                    }

                    for (int i = 0; i < indexFirstPlayer; i++)
                    {
                        IPlayerSeat playerSeat = playerSeats[i];
                        playerSeatsOrdered.Add(playerSeat);
                    }

                    playerSeats = playerSeatsOrdered;
                }
                //---

                //---> Create local game
                _lobbyGameLogic.CreateLocalGame(playerSeats);
            }
            else
            {
                GameConfiguration gameConf = new GameConfiguration();
                int[] duration = new int[] { 60, 3 * 60, 60 * 60 * 24, 60 * 60 * 24 * 7 };

                if (ui.QuickToggle.isOn)
                {
                    gameConf.name = PlayRealManager.Instance.Persistence.ConnectedPlayer.name + "'s Quick game";
                    gameConf.rated = ui.RankedToggle.isOn;
                    gameConf.min_players = ui.CountPlayersDropdown.value + 2;
                    gameConf.max_players = ui.CountPlayersDropdown.value + 2;
                    gameConf.game_mode = GameConfiguration.GameMode.ASYNCHRONOUS;
                    gameConf.timeout = 3 * 60;

                    //---> Create online game
                    _lobbyGameLogic.CreateOnlineGame(gameConf, string.Empty);

                    //---> Show waiting popup
                    ui.PopupWaitingGame.Show(gameConf.min_players);
                }
                else if (ui.AdvancedToggle.isOn)
                {
                    int[] minKarma = new int[] { 20, 40, 60 };
                    int[] minScore = new int[] { 0, 1000, 1100, 1200, 1300 };

                    gameConf.name = PlayRealManager.Instance.Persistence.ConnectedPlayer.name + "'s advanced game";
                    gameConf.min_players = ui.CountPlayersDropdown.value + 2;
                    gameConf.max_players = ui.CountPlayersDropdown.value + 2;
                    gameConf.first_player = ui.FirstPlayerDropdown.value + 1;
                    gameConf.min_karma = minKarma[ui.MinimumKarmaDropdown.value];
                    gameConf.min_rankscore = minScore[ui.MinimumScoreDropdown.value];
                    gameConf.@private = ui.PrivateToggle.isOn;
                    gameConf.rated = ui.RankedToggle.isOn;
                    gameConf.timeout = duration[ui.DurationDropdown.value];

                    gameConf.game_mode = GameConfiguration.GameMode.ASYNCHRONOUS;

                    string password = string.Empty;
                    if (ui.PrivateToggle.isOn)
                        password = ui.PrivatePasswordText.text;

                    //---> Create online game
                    _lobbyGameLogic.CreateOnlineGame(gameConf, password);

                    //---> Show waiting popup
                    ui.PopupWaitingGame.Show(gameConf.min_players);
                }
                else if (ui.InvitationToggle.isOn)
                {
                    gameConf.name = PlayRealManager.Instance.Persistence.ConnectedPlayer.name + "'s invitation game";
                    gameConf.rated = ui.RankedToggle.isOn;
                    gameConf.timeout = duration[ui.DurationDropdown.value];

                    int indexFirstPlayer = ui.InvitationLobbyPlayerSlots.FindIndex(lps => lps.ui.FirstPlayer.isOn);
                    gameConf.first_player = indexFirstPlayer > 0 ? indexFirstPlayer : 0;

                    gameConf.game_mode = GameConfiguration.GameMode.SYNCHRONOUS;

                    //--- Get DoW Ids of invited players
                    List<IPlayerSeat> playerSeats = ui.InvitationLobbyPlayerSlots.ConvertAll<IPlayerSeat>(lps => lps.GetPlayerSeat());
                    playerSeats.RemoveAll(lps => lps == null);

                    List<int> DoWIds = playerSeats.ConvertAll<int>(ps => ps.DoWPlayer.w_w_w_id);
                    //---

                    //---> Create Invitation game
                    _lobbyGameLogic.CreateInvitationGame(gameConf, DoWIds);

                    //--- Show waiting popup with friends
                    List<Player> players = playerSeats.ConvertAll<Player>(ps => ps.DoWPlayer);
                    ui.PopupWaitingGame.Show(players.Count, players);
                    //---
                }
            }
        }

        /// <summary>
        /// Join an open or active game
        /// </summary>
        public void JoinGame()
        {
            GameItem gameItem = null;
            string password = string.Empty;

            //---> Join an open game
            if (ui.JoinToggle.isOn)
            {
                gameItem = ui.OpenedGameItems.Find(gi => gi.ui.Toggle.isOn);

                if (gameItem.GameDetails.configuration.@private)
                    password = ui.OpenedGamePasswordInputField.text;

                _lobbyGameLogic.JoinGame(gameItem.GameDetails, password);
            }
            //---> Join an active game
            else
            {
                gameItem = ui.ResumeGameItems.Find(gi => gi.ui.Toggle.isOn);

                _lobbyGameLogic.ResumeSyncGame(gameItem.GameDetails);
            }

            ui.PopupWaitingGame.Show(gameItem.GameDetails.configuration.min_players, gameItem.GameDetails.players);
        }

        /// <summary>
        /// Accept an invitation
        /// </summary>
        public void AcceptInvitation()
        {
            _lobbyGameLogic.AcceptInvitation();

            IGameDetails gameDetails = PlayRealManager.Instance.Persistence.CurrentGameDetails;

            ui.PopupWaitingGame.Show(gameDetails.configuration.min_players, gameDetails.players);
        }

        /// <summary>
        /// Decline an invitation
        /// </summary>
        public void DeclineInvitation()
        {
            ui.PopupWaitingGame.Hide();

            _lobbyGameLogic.DeclineInvitation();
        }

        /// <summary>
        /// Leave the current waiting game
        /// </summary>
        public void LeaveGame()
        {
            ui.PopupWaitingGame.Hide();

            _lobbyGameLogic.LeaveCurrentWaitingGame();
        }

        /// <summary>
        /// Show the replay of a game
        /// </summary>
        public void ReplayGame()
        {
            ReplayGameItem replayGameItem = ui.ReplayGameItems.Values.ToList().Find(rgi => rgi.ui.Toggle.isOn);

            _lobbyGameLogic.ShowReplay(replayGameItem.GameState);
        }
        #endregion

        #region Logic events callbacks
        /// <summary>
        /// Event raised to refresh active games list
        /// </summary>
        /// <param name="statusReports"></param>
        private void LobbyGameLogic_LobbyResumeGameListEvent(List<StatusReport> statusReports)
        {
            List<IGameDetails> gamesDetails = statusReports.ConvertAll<IGameDetails>(sr => (IGameDetails)sr);
            RefreshGameList(gamesDetails, ui.ResumeGameItemsParent, ui.ResumeGameItems, ui.OpenedGameJoinButton, ui.SelectedOpenedGameDetails);
        }

        /// <summary>
        /// Event raised to refresh open games list
        /// </summary>
        /// <param name="gameList"></param>
        private void LobbyGameLogic_LobbyOpenGameListEvent(GameList gameList)
        {
            List<IGameDetails> gamesDetails = gameList.games.ConvertAll<IGameDetails>(sr => (IGameDetails)sr);
            RefreshGameList(gamesDetails, ui.OpenedGameItemsParent, ui.OpenedGameItems, ui.ResumeGameJoinButton, ui.SelectedResumeGameDetails);
        }

        /// <summary>
        /// Event raised when an invitation arrived
        /// </summary>
        /// <param name="invitedBy">Who invite me?</param>
        /// <param name="players">Players already in the game</param>
        private void LobbyGameLogic_InvitationArrivedEvent(Player invitedBy, List<Player> players)
        {
            ui.PopupWaitingGame.Show(
                String.Format("You are invited by {0}\r\nDo you accept the invitation?", invitedBy.name),
                players);
        }

        /// <summary>
        /// Event raised when the friend accept the invitation
        /// </summary>
        /// <param name="player"></param>
        private void LobbyGameLogic_InvitationRejectedEvent(Player player)
        {
            ui.PopupWaitingGame.PlayerRejectInvitation(player);
        }

        /// <summary>
        /// Event raised when the friend decline the invitation
        /// </summary>
        /// <param name="player"></param>
        private void LobbyGameLogic_InvitationAcceptedEvent(Player player)
        {
            if (IsDestroyed)
                return;

            ui.PopupWaitingGame.PlayerAcceptInvitation(player);
        }

        /// <summary>
        /// Event raised when a join denied error occured
        /// </summary>
        /// <param name="lobbyJoinDeniedRequest"></param>
        private void LobbyGameLogic_LobbyJoinDeniedEvent(LobbyJoinDeniedRequest lobbyJoinDeniedRequest)
        {
            ui.PopupWaitingGame.ShowDenied(lobbyJoinDeniedRequest.cause);
        }

        /// <summary>
        /// Event raised when a new player is coming in the waiting game
        /// </summary>
        /// <param name="lobbyNewPlayerRequest"></param>
        private void LobbyGameLogic_LobbyNewPlayerEvent(LobbyNewPlayerRequest lobbyNewPlayerRequest)
        {
            if (IsDestroyed)
                return;

            ui.PopupWaitingGame.Show(lobbyNewPlayerRequest.game.configuration.min_players, lobbyNewPlayerRequest.game.players);
        }

        /// <summary>
        /// Event raised when a player is leaving the waiting game
        /// </summary>
        /// <param name="leavingPlayer"></param>
        private void LobbyGameLogic_LobbyPlayerLeftGameEvent(Player leavingPlayer)
        {
            ui.PopupWaitingGame.RemovePlayer(leavingPlayer);
        }
        #endregion

        /// <summary>
        /// Dispose events and logic
        /// </summary>
        private void OnDestroy()
        {
            IsDestroyed = true;

            _lobbyGameLogic.LobbyResumeGameListEvent -= LobbyGameLogic_LobbyResumeGameListEvent;
            _lobbyGameLogic.LobbyOpenGameListEvent -= LobbyGameLogic_LobbyOpenGameListEvent;

            _lobbyGameLogic.InvitationAcceptedEvent -= LobbyGameLogic_InvitationAcceptedEvent;
            _lobbyGameLogic.InvitationRejectedEvent -= LobbyGameLogic_InvitationRejectedEvent;
            _lobbyGameLogic.LobbyNewPlayerEvent -= LobbyGameLogic_LobbyNewPlayerEvent;
            _lobbyGameLogic.LobbyPlayerLeftGameEvent -= LobbyGameLogic_LobbyPlayerLeftGameEvent;
            _lobbyGameLogic.LobbyJoinDeniedEvent -= LobbyGameLogic_LobbyJoinDeniedEvent;

            _lobbyGameLogic.Dispose();
        }
    }
}
