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

public class TetrisManager : MonoBehaviour
{
  #region 参数
  private const float MINIMALMOVESPACE = 0.2f;
  #endregion


  private float tmpdowntime = 0.5f;   //下落时间间隔
  private float tmplifttime = 0;      //左右移动
  private float gameTime;             //游戏时间

  private GameObject[] nowBlock;     //当前方块
  private GameObject[] nextBlock;      //下一个方块

  private int[,] myArray = new int[25, 10];

  private int[] myRow = new int[5];       //每个小方块的x坐标
  private int[] myCol = new int[5];       //每个小方块的y坐标

  private List<List<GameObject>> allSquart = new List<List<GameObject>>();      //所有方块
  private List<int> reList = new List<int>();         //需要移除的行数

  //是否可以移动
  private bool[] moveTypeL = new bool[4];
  private bool[] moveTypeR = new bool[4];
  private bool[] moveTypeD = new bool[4];

  // ==================================================

  private void Awake() => AwakeInit();
  private void Start() => StartInit();
  private void Update() => MoveBlock();

  // ==================================================
  #region 初始化区

  private void AwakeInit()
  {
    RandomNextBlock();
    return;
  }

  private void StartInit()
  {
    nowBlock = new GameObject[4];
    nextBlock = new GameObject[4];
    gameTime = Time.time;
    InitGame(); // 初始化信息
    NextBlock(); // 创建方块
    return;
  }

  #endregion
  // ==================================================
  #region 功能区

  /// <summary>
  /// 
  /// </summary>
  private void InitGame()
  {
    for (int i = 0; i < 25; i++) // 数组初始化
    {
      for (int j = 0; j < 10; j++)
      {
        myArray[i, j] = 0;
      }
    }
    for (int i = 0; i < 25; i++) // 方块容器分配空间
    {
      List<GameObject> list = new List<GameObject>();
      for (int j = 0; j < 10; j++)
      {
        GameObject obj = null;
        list.Add(obj);
      }

      allSquart.Add(list);
    }
    InitNowBlock();
    return;
  }

  /// <summary>
  /// ???
  /// 重置标记开关
  /// </summary>
  private void IntoMoveTypeOp()
  {
    for (int i = 0; i < 4; i++)
    {
      moveTypeD[i] = false;
      moveTypeL[i] = false;
      moveTypeR[i] = false;
    }
    return;
  }

  /// <summary>
  /// 删除下一个方块提示
  /// </summary>
  private void DeleatNextBlockTip()
  {
    for (int i = 0; i < 4; i++)
    {
      if (nextBlock[i] != null)
      {
        Destroy(nextBlock[i]);
      }
    }
    return;
  }

  #endregion
  // ==================================================
  #region 大方块管理区

  private int nextBlockType = 0; // 下一个方块的种类
  private int nextBlockRotationType = 0; // 下一个方块的方向
  private int nextBlockColorType = 0; // 下一个方块颜色

  /// <summary>
  /// 随机下一个方块的特性
  /// </summary>
  private void RandomNextBlock()
  {
    nextBlockType = Random.Range(0, 7);
    nextBlockRotationType = Random.Range(0, 4);
    nextBlockColorType = Random.Range(1, 6);
    return;
  }



  private int nowBlockType = 0; // 当前方块种类
  private int nowBlockRotationType = 0; // 当前方块方向
  private int nowBlockColorType = 0; // 当前方块颜色

  /// <summary>
  /// //初始化当前方块信息
  /// </summary>
  private void InitNowBlock()
  {
    nowBlockType = nextBlockType;
    nowBlockRotationType = nextBlockRotationType;
    nowBlockColorType = nextBlockColorType;
    return;
  }

  #endregion
  // ==================================================
  #region 大方块移动区

  /// <summary>
  /// 移动方块
  /// /// </summary>
  private void MoveBlock()
  {
    if (nowBlock == null)
    {
      return;
    }

    if (Input.GetKeyDown(KeyCode.DownArrow)) // 加快下落速度
    {
      tmpdowntime = tmpdowntime / 4;
    }
    if (Input.GetKeyUp(KeyCode.DownArrow)) // 速度恢复
    {
      tmpdowntime = tmpdowntime * 4;
    }

    if (Time.time - gameTime >= tmpdowntime) // 每隔固定时间，方块下落
    {
      gameTime = Time.time;
      MoveDown();
    }

    if (Input.GetKey(KeyCode.LeftArrow)) // 左移
    {
      if (Time.time - tmplifttime >= MINIMALMOVESPACE) // 最短触发时间
      {
        tmplifttime = Time.time;
        MoveLeft();
      }
    }
    else if (Input.GetKey(KeyCode.RightArrow)) // 右移
    {
      if (Time.time - tmplifttime >= MINIMALMOVESPACE)
      {
        tmplifttime = Time.time;
        MoveRight();
      }
    }

    if (Input.GetKeyDown(KeyCode.UpArrow))         //方块变形
    {
      if (nowBlock != null)
      {
        ChangeBlock();
      }
    }
    return;
  }



  private void MoveDown()
  {
    for (int i = 0; i < 4; i++) // 判断所有的四个方块下降是否有障碍物
    {
      if (myRow[i] > 0) // 避免数组越界
      {
        if (myArray[myRow[i] - 1, myCol[i]] == 0)
        {
          moveTypeD[i] = true;
        }
      }
    }
    if (moveTypeD[0] && moveTypeD[1] && moveTypeD[2] && moveTypeD[3])
    {
      for (int i = 0; i < 4; i++) // 四个小方块下移一格
      {
        moveTypeD[i] = false;
        nowBlock[i].transform.Translate(Vector3.down);
        myRow[i]--;
      }
      myRow[4]--;
    }
    else // 方块触底
    {
      TouchBottom();
    }
    IntoMoveTypeOp();
    return;
  }

  private void MoveLeft()
  {
    for (int i = 0; i < 4; i++) // 判断四个小方块左移是否有障碍
    {
      if (myCol[i] > 0)
      {
        if (myArray[myRow[i], myCol[i] - 1] == 0)
        {
          moveTypeL[i] = true;
        }
      }
    }
    if (moveTypeL[0] && moveTypeL[1] && moveTypeL[2] && moveTypeL[3]) // 向左移动一格
    {
      for (int i = 0; i < 4; i++)
      {
        moveTypeL[i] = false;
        nowBlock[i].transform.Translate(Vector3.left);
        myCol[i]--;
      }
      myCol[4]--;
    }
    IntoMoveTypeOp();
    return;
  }

  private void MoveRight()
  {
    for (int i = 0; i < 4; i++)
    {
      if (myCol[i] < 9)
      {
        if (myArray[myRow[i], myCol[i] + 1] == 0)
        {
          moveTypeR[i] = true;
        }
      }
    }
    if (moveTypeR[0] && moveTypeR[1] && moveTypeR[2] && moveTypeR[3])
    {
      for (int i = 0; i < 4; i++)
      {
        moveTypeR[i] = false;
        nowBlock[i].transform.Translate(Vector3.right); // 将方块右移
        myCol[i]++;
      }
      myCol[4]++;
    }
    IntoMoveTypeOp();
    return;
  }

  /// <summary>
  /// 放块触底
  /// </summary>
  private void TouchBottom()
  {
    for (int i = 0; i < 4; i++)
    {
      allSquart[myRow[i]][myCol[i]] = nowBlock[i];
      myArray[myRow[i], myCol[i]] = 1;
      nowBlock[i] = null;
    }
    if (IsGameOver()) // 游戏结束
    {
      TetrisGameManager.Instance.FinishGame();
    }
    else // 加载下一个方块
    {
      AddList();
      NextBlock();
    }
    return;
  }

  #endregion
  // ==================================================
  #region 小方块创建区

  private void NextBlock() // 创建方块
  {
    DeleatNextBlockTip();
    InitNowBlock();
    CreatBlock(nowBlock, 20, 5, nowBlockColorType, nowBlockType, nowBlockRotationType);  //创建游戏中的方块
    RandomNextBlock(); // 随机下一个方块属性
    CreatBlock(nextBlock, 13, 17, nextBlockColorType, nextBlockType, nextBlockRotationType);    //创建下一个方块提示
    return;
  }

  private void CreatBlock(GameObject[] blocks, int row, int col, int color, int type, int rot)      //创建方块(对象，坐标，颜色，形状，方向)
  {
    if (blocks == nowBlock) // 初始化坐标信息
    {
      myRow[4] = row;
      myCol[4] = col;
    }

    for (int i = 0; i < 4; i++) // 依次创建四个小方块
    {
      if (blocks == nowBlock)
      {
        myRow[i] = myRow[4];
        myCol[i] = myCol[4];
      }
      blocks[i] = Instantiate(Resources.Load<GameObject>("Cube" + color.ToString()));
      blocks[i].transform.position = new Vector3(col, row, 0);
    }
    SetPostion(blocks, type, rot); // 设置小方块初始位置
    return;
  }

  /// <summary>
  /// 设置方块
  /// </summary>
  /// <param name="block">对象</param>
  /// <param name="type">形状</param>
  /// <param name="rotation">方向</param>
  private void SetPostion(GameObject[] block, int type, int rotation)
  {
    switch (type)
    {
      case 0: // I
        CreatIBlock(block, rotation);
        break;
      case 1: // O
        CreatOBlock(block, rotation);
        break;
      case 2: // T
        CreatTBlock(block, rotation);
        break;
      case 3: // L
        CreatLBlock(block, rotation);
        break;
      case 4: // J
        CreatJBlock(block, rotation);
        break;
      case 5: // S
        CreatSBlock(block, rotation);
        break;
      case 6: // Z
        CreatZBlock(block, rotation);
        break;
    }
    return;
  }

  /// <summary>
  /// 创建I形方块
  /// </summary>
  /// <param name="obj"></param>
  /// <param name="rotationType"></param>
  private void CreatIBlock(GameObject[] obj, int rotationType)
  {
    if (rotationType == 0 || rotationType == 2) // 对应的两个方向
    {
      SkewingSquare(obj, 1, 1, 0);
      SkewingSquare(obj, 2, 2, 0);
      SkewingSquare(obj, 3, 3, 0);
    }
    else
    {
      SkewingSquare(obj, 1, 0, 1);
      SkewingSquare(obj, 2, 0, 2);
      SkewingSquare(obj, 3, 0, 3);
    }
    return;
  }

  /// <summary>
  /// 创建O形方块
  /// </summary>
  /// <param name="obj"></param>
  /// <param name="rotationType"></param>
  private void CreatOBlock(GameObject[] obj, int rotationType)
  {
    SkewingSquare(obj, 0, -1, 0);
    SkewingSquare(obj, 2, -1, 1);
    SkewingSquare(obj, 3, 0, 1);
    return;
  }

  /// <summary>
  /// 创建T形方块
  /// </summary>
  /// <param name="obj"></param>
  /// <param name="rotationType"></param>
  private void CreatTBlock(GameObject[] obj, int rotationType)
  {
    switch (rotationType) // 对应四种方向
    {
      case 0:
        SkewingSquare(obj, 0, -1, 0);
        SkewingSquare(obj, 2, 1, 0);
        SkewingSquare(obj, 3, 0, 1);
        break;
      case 1:
        SkewingSquare(obj, 1, 0, 1);
        SkewingSquare(obj, 2, 1, 1);
        SkewingSquare(obj, 3, 0, 2);
        break;
      case 2:
        SkewingSquare(obj, 1, -1, 1);
        SkewingSquare(obj, 2, 0, 1);
        SkewingSquare(obj, 3, 1, 1);
        break;
      case 3:
        SkewingSquare(obj, 1, -1, 1);
        SkewingSquare(obj, 2, 0, 1);
        SkewingSquare(obj, 3, 0, 2);
        break;
    }
    return;
  }

  /// <summary>
  /// 创建L形方块
  /// </summary>
  /// <param name="obj"></param>
  /// <param name="rotationType"></param>
  private void CreatLBlock(GameObject[] obj, int rotationType)
  {
    switch (rotationType)
    {
      case 0:
        SkewingSquare(obj, 0, -1, 0);
        SkewingSquare(obj, 2, -1, 1);
        SkewingSquare(obj, 3, -1, 2);
        break;
      case 1:
        SkewingSquare(obj, 0, -1, 0);
        SkewingSquare(obj, 1, -1, 1);
        SkewingSquare(obj, 2, 0, 1);
        SkewingSquare(obj, 3, 1, 1);
        break;
      case 2:
        SkewingSquare(obj, 1, 0, 1);
        SkewingSquare(obj, 2, 0, 2);
        SkewingSquare(obj, 3, -1, 2);
        break;
      case 3:
        SkewingSquare(obj, 0, -1, 0);
        SkewingSquare(obj, 2, 1, 0);
        SkewingSquare(obj, 3, 1, 1);
        break;
    }
    return;
  }

  /// <summary>
  /// 创建J形方块
  /// </summary>
  /// <param name="obj"></param>
  /// <param name="rotationType"></param>
  private void CreatJBlock(GameObject[] obj, int rotationType)
  {
    switch (rotationType)
    {
      case 0:
        SkewingSquare(obj, 0, -1, 0);
        SkewingSquare(obj, 2, 0, 1);
        SkewingSquare(obj, 3, 0, 2);
        break;
      case 1:
        SkewingSquare(obj, 0, -1, 0);
        SkewingSquare(obj, 2, 1, 0);
        SkewingSquare(obj, 3, -1, 1);
        break;
      case 2:
        SkewingSquare(obj, 1, 0, 1);
        SkewingSquare(obj, 2, 0, 2);
        SkewingSquare(obj, 3, 1, 2);
        break;
      case 3:
        SkewingSquare(obj, 0, 1, 0);
        SkewingSquare(obj, 1, -1, 1);
        SkewingSquare(obj, 2, 0, 1);
        SkewingSquare(obj, 3, 1, 1);
        break;
    }
    return;
  }

  /// <summary>
  /// 创建S形方块
  /// </summary>
  /// <param name="obj"></param>
  /// <param name="rotationType"></param>
  private void CreatSBlock(GameObject[] obj, int rotationType)
  {
    if (rotationType == 0 || rotationType == 2)
    {
      SkewingSquare(obj, 0, -1, 0);
      SkewingSquare(obj, 2, 0, 1);
      SkewingSquare(obj, 3, 1, 1);
    }
    else
    {
      SkewingSquare(obj, 1, -1, 1);
      SkewingSquare(obj, 2, 0, 1);
      SkewingSquare(obj, 3, -1, 2);
    }
    return;
  }

  /// <summary>
  /// 创建Z形方块
  /// </summary>
  /// <param name="obj"></param>
  /// <param name="rotationType"></param>
  private void CreatZBlock(GameObject[] obj, int rotationType)
  {
    if (rotationType == 0 || rotationType == 2)
    {
      SkewingSquare(obj, 1, 1, 0);
      SkewingSquare(obj, 2, -1, 1);
      SkewingSquare(obj, 3, 0, 1);
    }
    else
    {
      SkewingSquare(obj, 0, -1, 0);
      SkewingSquare(obj, 1, -1, 1);
      SkewingSquare(obj, 2, 0, 1);
      SkewingSquare(obj, 3, 0, 2);
    }
    return;
  }

  #endregion
  // ==================================================
  #region  小方块控制区

  /// <summary>
  /// 移动每个小方块的位置
  /// </summary>
  /// <param name="obj"></param>
  /// <param name="index"></param>
  /// <param name="x"></param>
  /// <param name="y"></param>
  private void SkewingSquare(GameObject[] obj, int index, int x, int y)
  {
    obj[index].transform.Translate(Vector3.right * x); // 移动方块的位置
    obj[index].transform.Translate(Vector3.up * y);
    if (obj == nowBlock)
    {
      myRow[index] += y; // 更新方块在数组中的坐标
      myCol[index] += x;
    }
    return;
  }

  /// <summary>
  /// 重置方块
  /// </summary>
  private void ResetSquare()
  {
    for (int i = 0; i < 4; i++) // 将所有小方块移动到中心位置
    {
      myRow[i] = myRow[4];
      myCol[i] = myCol[4];
      nowBlock[i].transform.position = new Vector3(myCol[4], myRow[4], 0);
    }
    return;
  }

  #endregion
  // ==================================================
  #region 小方块变形区

  /// <summary>
  /// 检测方块是否可以变形
  /// </summary>
  private void ChangeBlock()
  {
    bool ison = false;
    switch (nowBlockType)
    {
      case 0: // I形
        ison = CanIBlockTransform();
        break;
      case 1: // O形方块无法变形
        ison = false;
        break;
      case 2: // T形
        ison = CanTBlockTransform();
        break;
      case 3: // L形
        ison = CanLBlockTransform();
        break;
      case 4: // J形
        ison = CanJBlockTransform();
        break;
      case 5: // S形
        ison = CanSBlockTransform();
        break;
      case 6: // Z形
        ison = CanZBlockTransform();
        break;
    }
    if (ison) // 检测是否可以变形
    {
      ResetSquare();      //重置所有小方块
      nowBlockRotationType++;     //改变方块方向
      if (nowBlockRotationType >= 4)
      {
        nowBlockRotationType = 0;
      }
      SetPostion(nowBlock, nowBlockType, nowBlockRotationType);       //重新设置四个小方块的位置
    }
    return;
  }



  /// <summary>
  /// 判断I形方块是否可以变形
  /// </summary>
  /// <returns></returns>
  private bool CanIBlockTransform()
  {
    switch (nowBlockRotationType)
    {
      case 0:
        if (CanChange(0, 1) && CanChange(0, 2) && CanChange(0, 3))
        {
          return true;
        }
        break;
      case 1:
        if (CanChange(1, 0) && CanChange(2, 0) && CanChange(3, 0))
        {
          return true;
        }
        break;
      case 2:
        if (CanChange(0, 1) && CanChange(0, 2) && CanChange(0, 3))
        {
          return true;
        }
        break;
      case 3:
        if (CanChange(1, 0) && CanChange(2, 0) && CanChange(3, 0))
        {
          return true;
        }
        break;
    }
    return false;
  }

  /// <summary>
  /// 判断T形方块是否可以变形
  /// </summary>
  /// <returns></returns>
  private bool CanTBlockTransform()
  {
    switch (nowBlockRotationType)
    {
      case 0:
        if (CanChange(0, 2) && CanChange(1, 1))
        {
          return true;
        }
        break;
      case 1:
        if (CanChange(-1, 1))
        {
          return true;
        }
        break;
      case 2:
        if (CanChange(0, 2))
        {
          return true;
        }
        break;
      case 3:
        if (CanChange(-1, 0) && CanChange(1, 0))
        {
          return true;
        }
        break;
    }
    return false;
  }

  /// <summary>
  /// 判断L形方块是否可以变形
  /// </summary>
  /// <returns></returns>
  private bool CanLBlockTransform()
  {
    switch (nowBlockRotationType)
    {
      case 0:
        if (CanChange(0, 1) && CanChange(1, 1))
        {
          return true;
        }
        break;
      case 1:
        if (CanChange(-1, 2) && CanChange(0, 2))
        {
          return true;
        }
        break;
      case 2:
        if (CanChange(-1, 0) && CanChange(1, 0) && CanChange(1, 1))
        {
          return true;
        }
        break;
      case 3:
        if (CanChange(-1, 2) && CanChange(-1, 1))
        {
          return true;
        }
        break;
    }
    return false;
  }

  /// <summary>
  /// 判断J形方块是否可以变形
  /// </summary>
  /// <returns></returns>
  private bool CanJBlockTransform()
  {
    switch (nowBlockRotationType)
    {
      case 0:
        if (CanChange(-1, 1) && CanChange(1, 0))
        {
          return true;
        }
        break;
      case 1:
        if (CanChange(0, 1) && CanChange(0, 2) && CanChange(1, 2))
        {
          return true;
        }
        break;
      case 2:
        if (CanChange(-1, 1) && CanChange(1, 0) && CanChange(1, 1))
        {
          return true;
        }
        break;
      case 3:
        if (CanChange(-1, 0) && CanChange(0, 2))
        {
          return true;
        }
        break;
    }
    return false;
  }

  /// <summary>
  /// 判断S形方块是否可以变形
  /// </summary>
  /// <returns></returns>
  private bool CanSBlockTransform()
  {
    if (nowBlockRotationType == 0 || nowBlockRotationType == 2)
    {
      if (CanChange(-1, 1) && CanChange(-1, 2))
      {
        return true;
      }
    }
    else
    {
      if (CanChange(-1, 0) && CanChange(1, 1))
      {
        return true;
      }
    }
    return false;
  }

  /// <summary>
  /// 判断Z形方块是否可以变形
  /// </summary>
  /// <returns></returns>
  private bool CanZBlockTransform()
  {
    if (nowBlockRotationType == 0 || nowBlockRotationType == 2)
    {
      if (CanChange(-1, 0) && CanChange(0, 2))
      {
        return true;
      }
    }
    else
    {
      if (CanChange(0, 0) && CanChange(1, 0))
      {
        return true;
      }
    }
    return false;
  }

  /// <summary>
  /// 检查该区域是否有方块
  /// </summary>
  /// <param name="index1"></param>
  /// <param name="index2"></param>
  /// <returns></returns>
  private bool CanChange(int index1, int index2)
  {
    int row = myRow[4] + index2;
    int col = myCol[4] + index1;

    if ((row >= 0) && (row < 20) && (col >= 0) && (col < 10)) // 避免数组越界
    {
      if (myArray[row, col] != 1) // 该区域没有方块
      {
        return true;
      }
      else
      {
        return false;
      }
    }
    else
    {
      return false;
    }
  }

  #endregion
  // ==================================================
  #region 游戏逻辑区

  /// <summary>
  /// 检测是否游戏结束
  /// </summary>
  /// <returns></returns>
  private bool IsGameOver()
  {
    bool result = false;
    for (int i = 0; i < 10; i++)
    {
      if (myArray[19, i] == 1)
      {
        result = true;
      }
    }
    return result;
  }

  private void AddList()
  {
    for (int i = 0; i < 20; i++) // 统计要移除的行
    {
      int num = 0;
      for (int j = 0; j < 10; j++) // 该行都有方块时，进行移除
      {
        if (myArray[i, j] == 1)
        {
          num++;
        }
      }
      if (num == 10)
      {
        reList.Add(i); // 添加进容器
        TetrisScoreManager.Instance.AddScore(1);
      }
    }
    if (reList.Count > 0) // 有需要移除的行时，进行移除操作
    {
      RemoveBlock();
      TetrisScoreManager.Instance.UpdateScoreText();
    }
    return;
  }

  /// <summary>
  /// 移除方块
  /// </summary>
  private void RemoveBlock()
  {
    int count = reList.Count;

    for (int k = 0; k < count; k++)         //循环移除所有行
    {
      {
        for (int i = 0; i < 10; i++)
        {
          Destroy(allSquart[reList[0]][i]);       //删除该行的方块
          myArray[reList[0], i] = 0;              //标记数组归为零
        }
        for (int i = reList[0]; i < 20; i++)        //讲该行上面的所有行下移
        {
          for (int j = 0; j < 10; j++)
          {
            allSquart[i][j] = allSquart[i + 1][j];      //将对象数组重新赋值
            if (allSquart[i][j] != null)
            {
              allSquart[i][j].transform.Translate(Vector3.down);      //下移操作
            }
            myArray[i, j] = myArray[i + 1, j];          //标记数组重新赋值
          }

        }
        reList.RemoveAt(0);         //移除容器里的数值
        for (int i = 0; i < reList.Count; i++)       //剩余需操作行数减一
        {
          reList[i]--;
        }
      }
    }
    return;
  }

  #endregion
  // ==================================================
  #region 游戏逻辑区

  /// <summary>
  /// 
  /// </summary>
  public class BlockInfo
  {
    public int typeIndex;
    public int rotationTypeIndex;
    public int colorTypeIndex;
  }

  #endregion
}