// 地形（ジオメトリ）の制御
using UnityEngine;
using System.Collections;
using System;

public class Geo : MonoBehaviour {

    public GeoData geoData; // 地形データ
    MapManager mapMan;      // マップマネージャーへのアクセス用
    public Vector3 meshMul; // 地形メッシュの拡大率

    public Vector2 centerLotLat;    // 世界中心の緯度経度

    public Vector2 diffLL;      // 差分
    public Vector2 lowLL;       // 低緯経度
    public Vector2 highLL;      // 高緯経度
    public Vector2 centerLL;    // 中央緯経度

    private void Awake()    // 起動直後の処理
    {
        centerLotLat = new Vector2(0, 0);   // 世界の中心緯度経度の初期データ（ダミー）
        meshMul = new Vector3(1, 0.08f, 1); // メッシュの拡大率の初期データ（ダミー）
        mapMan = GameObject.Find("MapManager").GetComponent<MapManager>();
    }

    void Update()   // 通常処理
    {
        AdjustPosition();   // 地形の位置補正
    }

    private void AdjustPosition()    // 地形位置補正処理
    {
        if ((geoData == null) || (geoData.size == 0))   // 地形データが用意されるまで処理しない
            return;

        meshMul = new Vector3(1, mapMan.magBump, 1);    // メッシュ拡大率の更新
        float ux = (centerLL.x - mapMan.lookLongitude) * ((geoData.meshWidth * meshMul.x) / diffLL.x);
        float uy = (centerLL.y - mapMan.lookLatitude) * ((geoData.meshHeight * meshMul.z) / diffLL.y);
        transform.position = new Vector3(ux, 0, uy);
        transform.localScale = meshMul;
    }

    public bool IsOnMap(Vector2 ll) // マップ範囲チェック（緯度経度がマップの範囲にあるか）
    {
        if ((ll.x < lowLL.x) || (ll.x > highLL.x) || (ll.y < lowLL.y) || (ll.y > highLL.y)) return false;
        return true;
    }

    public Vector3 GetMapPos(Vector2 ll)    // 指定緯度経度の標高取得
    {
        int mw = geoData.meshWidth;
        int mh = geoData.meshHeight;
        float xi = (ll.x - lowLL.x) / diffLL.x;
        float yi = (ll.y - lowLL.y) / diffLL.y;
        float xo = (xi - 0.5f) * (mw * meshMul.x);
        float yo = (yi - 0.5f) * (mh * meshMul.z);
        float ho = geoData.altitude[Mathf.Clamp((int)((1.0f - yi) * mh), 0, mh - 1) * mw + Mathf.Clamp((int)(xi * mw - 1), 0, mw)] * meshMul.y;
        return new Vector3(xo, ho, yo);
    }

    public void Load(string URL)    // 地形データのダウンロードリクエスト
    {
        if (geoData != null)    // 重複禁止
        {
            return;
        }
        geoData = new GeoData(URL); // 地形データ領域の生成
        if (geoData != null)
        {
            StartCoroutine(Connect());  // ダウンロードの開始
        }
    }

    private IEnumerator Connect()   // ダウンロード処理のコルーチン
    {
        var www = new WWW(geoData.url + ".csv");    // 標高データCSVのロード
        yield return www;

        var www2 = new WWW(geoData.url + ".png");   // 航空写真Pngのロード
        yield return www2;
        geoData.texture = www2.texture;

        //csv
        System.StringSplitOptions option = StringSplitOptions.RemoveEmptyEntries;   // カンマと空データを無効にする
        string[] lines = www.text.Split(new char[] { '\r', '\n' }, option);         // 行に分ける

        geoData.lowLongitude  = float.Parse(lines[0]);    // 低経度の取得
        geoData.lowLatitude   = float.Parse(lines[1]);    // 低緯度の取得
        geoData.highLongitude = float.Parse(lines[2]);    // 高経度の取得
        geoData.highLatitude  = float.Parse(lines[3]);    // 高経度の取得

        lowLL = new Vector2(geoData.lowLongitude, geoData.lowLatitude);     // 低経緯度
        highLL = new Vector2(geoData.highLongitude, geoData.highLatitude);  // 高経緯度
        centerLL = (lowLL + highLL) / 2.0f;                                 // 中央経緯度
        diffLL = highLL - lowLL;                                            // 経緯度の幅

        geoData.meshWidth = int.Parse(lines[4]) / 2;      // メッシュの幅
        geoData.meshHeight = int.Parse(lines[5]) / 2;     // メッシュの高さ
        geoData.size = geoData.meshWidth * geoData.meshHeight;  // メッシュデータサイズ
        geoData.altitude = new float[geoData.size];             // 標高データの展開
        for (int y = 0; y < geoData.meshHeight; y++)
        {
            for (int x = 0; x < geoData.meshWidth; x++)
            {
                geoData.altitude[y * geoData.meshWidth + x] =
                    float.Parse(lines[(x * 2 + y * geoData.meshWidth * 2) + 6]);
            }
        }
    }

    public void Build() // 地形オブジェクトモデルの構築
    {
        var mesh = new Mesh();  // 空メッシュ
        Vector3[] workv3 = new Vector3[geoData.meshWidth * geoData.meshHeight]; // 頂点座標作成用
        Vector2[] workv2 = new Vector2[geoData.meshWidth * geoData.meshHeight]; // テクスチャＵＶ座標作成用
        int[] worki = new int[(geoData.meshWidth - 1) * (geoData.meshHeight - 1) * 2 * 3];  // 三角ポリゴン作成用
        for (int y = 0; y < geoData.meshHeight; y++)    // 頂点ごとのデータ構築
        {
            for (int x = 0; x < geoData.meshWidth; x++)
            {
                workv3[y * geoData.meshWidth + x] =
                    new Vector3(x - (geoData.meshWidth / 2),
                                geoData.altitude[y * geoData.meshWidth + x],
                                -y + (geoData.meshHeight / 2));
                workv2[y * geoData.meshWidth + x] =
                    new Vector2((x) / (1.0f * (geoData.meshWidth - 1)),
                    1 - (y) / (1.0f * (geoData.meshHeight - 1)));
            }
        }
        for (int y = 0; y < (geoData.meshHeight - 1); y++)  // 頂点を連結してポリゴンを構築
        {
            for (int x = 0; x < (geoData.meshWidth - 1); x++)
            {
                worki[(y * (geoData.meshWidth - 1) + x) * 6 + 5] = geoData.meshWidth + 1 + x + y * geoData.meshWidth;
                worki[(y * (geoData.meshWidth - 1) + x) * 6 + 4] = 1 + x + y * geoData.meshWidth;
                worki[(y * (geoData.meshWidth - 1) + x) * 6 + 3] = geoData.meshWidth + x + y * geoData.meshWidth;
                worki[(y * (geoData.meshWidth - 1) + x) * 6 + 2] = geoData.meshWidth + x + y * geoData.meshWidth;
                worki[(y * (geoData.meshWidth - 1) + x) * 6 + 1] = 1 + x + y * geoData.meshWidth;
                worki[(y * (geoData.meshWidth - 1) + x) * 6 + 0] = 0 + x + y * geoData.meshWidth;
            }
        }
        mesh.vertices = workv3; // メッシュ情報として合成
        mesh.uv = workv2;
        mesh.triangles = worki;

        GetComponent<MeshFilter>().sharedMesh = mesh;   // 地形オブジェクトを生成
        GetComponent<MeshCollider>().sharedMesh = mesh; // メッシュコライダーを生成（拡張用だけど、今は要らないか？）
        GetComponent<Renderer>().material.mainTexture = geoData.texture;    // テクスチャを貼り付け
    }
}
