﻿/*
    Translation Exerciser - App to learn translations by repetition
    Copyright (C) 2017 Joakim Johansson

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

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

    See LICENSE file or GNU General Public License at <http://www.gnu.org/licenses/>.
*/

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class WordSlideMain : MonoBehaviour {
    public Camera mainCam;
    public GameObject categoryParent;
    public GameObject categoryCont;
    public GameObject categoryPrefab;
    public MainScreenMovements mover;
    public GameObject letterBoxPrefab;
    public GameObject letterBoxCont;

    private List<Translation> chosenTranslations;
    private string chosenCat = "";
    private int chosenCount = 0;
    private List<LetterBox> letterboxes;

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }

    public void Show(bool reset = false) {
        transform.SetAsLastSibling();
        gameObject.SetActive(true);
        mover.Show(Vector3.down);

        if (reset == true || chosenCat == "") {
            Reset();
        }
    }

    public void Hide(bool disable = false, float delay = 0f, float duration = 0f) {
        if (disable) {
            mover.Hide(delay, duration);
        } else {
            mover.Hide(Vector3.down, delay, duration);
        }
    }

    void Reset() {
        chosenTranslations = new List<Translation>();
        chosenCat = "";
        ShowCategories();
    }

    void ShowCategories() {
        categoryCont.SetActive(true);
        for (int i = categoryCont.transform.childCount - 1; i > 0; i--) { //Leave one because it is the heading.
            GameObject c = categoryCont.transform.GetChild(i).gameObject;
            Destroy(c);
        }
        Translations.ListCategories.ForEach((cat) => {
            GameObject catChoice = Instantiate(categoryPrefab, categoryCont.transform);
            CategorySelectionBtn CatSel = catChoice.GetComponent<CategorySelectionBtn>();
            CatSel.SetCat(Helpers.Capitalize(cat));
            CatSel.chooseCat = (value) => { ChooseCat(value); return ""; };
        });
    }

    public void ChooseCat(string cat) {
        chosenCat = cat;
        categoryCont.SetActive(false);
        Hide(false, 0, 0.2f);

        chosenTranslations = Translations.GetByCategory(chosenCat);

        PickWordsForBoard();
    }

    void PickWordsForBoard() {
        List<Translation> words = new List<Translation>();
        List<Translation> allTranslations = new List<Translation>(chosenTranslations);

        int amountToPick = (allTranslations.Count < 6) ? allTranslations.Count : 6;
        if (chosenCount > 0) {
            amountToPick = (chosenCount <= allTranslations.Count) ? chosenCount : allTranslations.Count;
        }
        for (int i = 0; i < amountToPick; i++) {
            Translation t = allTranslations[Random.Range(0, allTranslations.Count)];
            words.Add(t);
            allTranslations.Remove(t);
        }

        GenerateBoard(words);
    }

    void GenerateBoard(List<Translation> words) {
        int maxWordLength = Translations.GetMostChars(words, Globals.toLang);

        List<char[]> cols = new List<char[]>();

        for (int i = 0; i < maxWordLength; i++) {
            cols.Add(new char[words.Count]);
        }
        for (int i = 0; i < words.Count; i++) {
            string word = words[i].GetWord(Globals.toLang);
            int l = word.Length;
            int start = Mathf.FloorToInt((maxWordLength - l) / 2);
            char[] chars = word.ToCharArray();
            for (int letterIndex = 0; letterIndex < l; letterIndex++) {
                int colIndex = start + letterIndex;

                cols[colIndex][i] = chars[letterIndex];
            }
        }

        cols.ForEach((col) => {
            col.Shuffle();
        });

        letterboxes = new List<LetterBox>();
        AddLetterBoxes(cols);
    }

    void AddLetterBoxes(List<char[]> cols) {
        for (int i = letterBoxCont.transform.childCount - 1; i > 0; i--) {
            //Leave one because it is the background.
            GameObject c = letterBoxCont.transform.GetChild(i).gameObject;
            Destroy(c);
        }

        for (int colIndex = 0; colIndex < cols.Count; colIndex++) {
            char[] col = cols[colIndex];
            for (int rowIndex = 0; rowIndex < col.Length; rowIndex++) {
                if (col[rowIndex] != '\0') { 
                    GameObject letterBoxGO = (GameObject)Instantiate(letterBoxPrefab, letterBoxCont.transform);
                    LetterBox lb = letterBoxGO.GetComponent<LetterBox>();
                    letterboxes.Add(lb);
                    lb.mainCam = mainCam;
                    lb.main = this;
                    lb.col = colIndex - 4;
                    lb.row = rowIndex;
                    lb.letter = col[rowIndex];
                }
            }
        }
    }

    public void LetterBoxMoved(LetterBox lb, Vector3 delta) {
        float deltaY = delta.y;
        int col = lb.col;

        GetLetterBoxesInCol(col).ForEach((lbToMove) => {
            lbToMove.Move(deltaY);
        });
    }

    public void LetterBoxFinishedMoving(LetterBox lb, int shift = 0) {
        int col = lb.col;

        GetLetterBoxesInCol(col).ForEach((lbToShift) => {
            lbToShift.Shift(shift);
        });

        CheckForValidWord();
    }

    public void CheckForValidWord() {
        string currentWord = "";
        List<LetterBox> currentLbs = GetLetterBoxesInRow(0);
        currentLbs.ForEach((lb) => {
            currentWord += lb.letter.ToString();
        });

        chosenTranslations.ForEach((t) => {
            if (t.GetWord(Globals.toLang) == currentWord) {
                //Word is valid. set the letters to used.
                currentLbs.ForEach((lb) => {
                    lb.SetUsed();
                });
            }
        });

        bool usedAll = true; 
        letterboxes.ForEach((lb) => {
            if (lb.isUsed == false) {
                usedAll = false;
            }
        });

        if (usedAll == true) {
            //All boxes have been used, the board is finished.
            Show(true);
        }
    }

    public string GetCurrentWord() {
        string currentWord = "";

        GetLetterBoxesInRow(0).ForEach((lb) => {
            currentWord += lb.letter.ToString();
        });

        return currentWord;
    }

    List<LetterBox> GetLetterBoxesInCol(int col) {
        List<LetterBox> lbs = new List<LetterBox>();

        letterboxes.ForEach((lb) => {
            if (lb.col == col) {
                lbs.Add(lb);
            }
        });

        return lbs;
    }
    List<LetterBox> GetLetterBoxesInRow(int row) {
        List<LetterBox> lbs = new List<LetterBox>();

        letterboxes.ForEach((lb) => {
            if (lb.row == row) {
                lbs.Add(lb);
            }
        });

        lbs.Sort((LetterBox a, LetterBox b) => {
            return a.col - b.col;
        });

        return lbs;
    }

}
