using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System.Linq;

public class CameraMoveCenter : MonoBehaviour {

    public GameObject centerLines;
    public GameObject virtualEndoscope;
    public GameObject lightSource;


    //中心点たどるよう変数
    List<Vector3> worldVertices = new List<Vector3>();
    List<Vector3> sortedWorldVertices = new List<Vector3>();
    List<float> distanceOfPointsList = new List<float>();
    int posIndex = 0;

    //csv出力用
    float nomalizedNum = (125.6f / 12.4f);
    int whileCount = 0;
    string basePath = "C:\\UnityWorkSpace\\";
    float beforeDistance = 0.0f;

    //ボタン制御用
    bool Is_starting = false;

    // Use this for initialization
    void Start () { 

        var moveMatrix = centerLines.transform.localToWorldMatrix;
        var centerVertices = centerLines.GetComponent<MeshFilter>().mesh.vertices;

        foreach (var vertice in centerVertices)
        {
            worldVertices.Add(moveMatrix.MultiplyPoint3x4(vertice));
        }
        sortedWorldVertices = sortNearestPoint(virtualEndoscope.transform.position, worldVertices);

        distanceOfPointsList = getDistanceOfPointList(sortedWorldVertices);

        if (worldVertices != null)
        {
            virtualEndoscope.transform.position = sortedWorldVertices[0];
            lightSource.transform.position = sortedWorldVertices[0];
            virtualEndoscope.transform.LookAt(sortedWorldVertices[1]);
        }
        else Debug.Log("ヌル！！！");

        InvokeRepeating("updateForInvoke", 0, 0.0333f);
    }
	

    
    /*
     * 返り値: List<Vector3>
     * 引数: カメラに近い順番に並んだ座標値のList
     * 機能: 座標間の距離のListを作成する
     */
    List<float> getDistanceOfPointList(List<Vector3> movePoints)
    {
        var pointsDistanceList = new List<float>();

        for(int i =0;i < movePoints.Count - 1; i++)
        {
            pointsDistanceList.Add((movePoints[i + 1] - movePoints[i]).magnitude);
        }

        return pointsDistanceList;
    }


    /*
     * 返り値: float
     * 引数: CSVファイルへのパス　string
     * 機能: 挿入距離を取得
     */
     float getInsertionDistance(string pathToCSV)
    {
        float unityMoveDistance = 0.0f;
        float moveDistance = 0.0f;

        if (File.Exists(pathToCSV))
        {
            var moveList = new List<string>();
            var sr = new StreamReader(pathToCSV);

            while(!sr.EndOfStream)
            {
                string line = sr.ReadLine();
                string[] values = line.Split(',');
                moveList.AddRange(values);
            }

            moveDistance = float.Parse(moveList[0]);

            if(beforeDistance != moveDistance)
            {
                unityMoveDistance = moveDistance * nomalizedNum;
                //unityMoveDistance = moveDistance;
                beforeDistance = moveDistance;
            }

            moveList.Clear();
            sr.Close();

            whileCount++;
        }

        return unityMoveDistance;
    }


    /*
     * 返り値: List<Vector3>
     * 引数: 最初のカメラ位置(Vector3), 世界系での中心座標(List<Vector3>)
     * 機能: カメラから近い順にソートする(処理の都合上，第2引数のListは空になる．Copyとか足せばどうにかなる)
     */
    List<Vector3> sortNearestPoint(Vector3 initCameraPoint, List<Vector3> centerVertices)
    {
        var sortedCenterVertices = new List<Vector3>();
        float minDistance = float.MaxValue;
        var nearestVertex = new Vector3();

        centerVertices.Distinct();

        foreach (var vertex in centerVertices)
        {
            float tempMagnitude = (vertex - initCameraPoint).magnitude;
            if (tempMagnitude < minDistance)
            {
                nearestVertex = vertex;
                minDistance = tempMagnitude;
            }
        }
        sortedCenterVertices.Add(nearestVertex);
        worldVertices.Remove(nearestVertex);

        var currentVertex = nearestVertex;
        int initialCount = centerVertices.Count;

        for (int i = 0; i < initialCount; i++)
        {
            minDistance = float.MaxValue;

            foreach (var vertex in worldVertices)
            {
                float tempMagnitude = (vertex - currentVertex).magnitude;
                if (tempMagnitude < minDistance)
                {
                    nearestVertex = vertex;
                    minDistance = tempMagnitude;
                }
            }
            sortedCenterVertices.Add(nearestVertex);
            worldVertices.Remove(nearestVertex);
            currentVertex = nearestVertex;
        }

        return sortedCenterVertices;
    }

    /*
     *  返り値: List<Vector3>
     */


    /*
     * 返り値: Vector3
     * 引数: 世界系の中心座標(List<Vector3>), その座標系でのインデックス(int)
     * 機能:LookAt先のvectorを演算，自分の先のベクターを利用．ハイパーパラメータとしてVector間隔，重心決定範囲を設定
     */
     Vector3 calcBarycenter(List<Vector3> centers, int index)
    {
        // ハイパーパラメータ
        int interval = 5;
        int range = centers.Count / 50;

        //以下処理
        var tempVectors = new List<Vector3>();
        var maxIndex = centers.Count;

        for(int i = 0; i < range; i++)
        {
            if (maxIndex <= (index + (i * interval))) break;
            tempVectors.Add(centers[index + (i * interval)]);
        }

        return new Vector3(tempVectors.Average(V => V.x), tempVectors.Average(V => V.y), tempVectors.Average(V => V.z));
    }


    /*
     * 返り値: 無し
     * 引数: 無し
     * 機能: InvokeRepeating用，実質Update内の記述
     */
     void updateForInvoke()
    {
        string pathToCSV = basePath + whileCount.ToString() + ".csv";
        float insertionDistance = getInsertionDistance(pathToCSV);
        Debug.Log(posIndex);

        if(0.0f < insertionDistance && posIndex != sortedWorldVertices.Count - 1)
        {
            float nearestDistance = (virtualEndoscope.transform.position - sortedWorldVertices[posIndex+1]).magnitude;

            if (insertionDistance <= nearestDistance)
            {
                virtualEndoscope.transform.LookAt(sortedWorldVertices[posIndex + 1]);
                virtualEndoscope.transform.Translate(0.0f, 0.0f, insertionDistance);
            }
            else
            {
                insertionDistance -= nearestDistance;
                posIndex++;

                while (true)
                {
                    if(posIndex == sortedWorldVertices.Count - 1)
                    {
                        virtualEndoscope.transform.position = sortedWorldVertices[posIndex];
                        lightSource.transform.position = virtualEndoscope.transform.position;

                        break;
                    }
                    else if(insertionDistance < distanceOfPointsList[posIndex])
                    {
                        virtualEndoscope.transform.position = sortedWorldVertices[posIndex];
                        // ここは理想はトランスレイトではなく，ポジションに変える．そうすれば視界も安定する．
                        virtualEndoscope.transform.LookAt(sortedWorldVertices[posIndex + 1]);
                        virtualEndoscope.transform.Translate(0.0f, 0.0f, insertionDistance);
                        // virtualEndoscope.transform.LookAt(calcBarycenter(sortedWorldVertices, posIndex));
                        lightSource.transform.position = virtualEndoscope.transform.position;

                        break;
                    }

                    insertionDistance -= distanceOfPointsList[posIndex];
                    posIndex++;
                }
            }

        }
        else if(insertionDistance < 0.0f && posIndex != 0)
        {
            insertionDistance = -insertionDistance;
            float nearestDistance = (virtualEndoscope.transform.position - sortedWorldVertices[posIndex - 1]).magnitude;

            if (insertionDistance <= nearestDistance)
            {
                virtualEndoscope.transform.LookAt(sortedWorldVertices[posIndex + 1]);
                virtualEndoscope.transform.Translate(0.0f, 0.0f, -insertionDistance);
            }
            else
            {
                insertionDistance -= nearestDistance;

                while (true)
                {
                    if(posIndex == 0)
                    {
                        virtualEndoscope.transform.position = sortedWorldVertices[posIndex];
                        lightSource.transform.position = virtualEndoscope.transform.position;

                        break;
                    }
                    else if (insertionDistance < distanceOfPointsList[posIndex - 1])
                    {
                        float tempRatio = insertionDistance / distanceOfPointsList[posIndex - 1];
                        Vector3 tempVector = sortedWorldVertices[posIndex] - sortedWorldVertices[posIndex - 1];
                        virtualEndoscope.transform.position = new Vector3(sortedWorldVertices[posIndex].x - (tempVector.x * tempRatio), sortedWorldVertices[posIndex].y - (tempVector.y * tempRatio), sortedWorldVertices[posIndex].z - (tempVector.z * tempRatio));
                        //virtualEndoscope.transform.LookAt(calcBarycenter(sortedWorldVertices, posIndex));
                        virtualEndoscope.transform.LookAt(sortedWorldVertices[posIndex]);
                        lightSource.transform.position = virtualEndoscope.transform.position;

                        posIndex--;

                        break;
                    }

                    insertionDistance -= distanceOfPointsList[posIndex - 1];
                    posIndex--;
                }
            }
        }
    }
}
