/*
 * ExternalReceiver
 * https://sabowl.sakura.ne.jp/gpsnmeajp/
 *
 * MIT License
 * 
 * Copyright (c) 2019 gpsnmeajp
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
#pragma warning disable 0414,0219
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Profiling;


namespace EVMC4U
{
    public class CommunicationValidator : MonoBehaviour, IExternalReceiver
    {
        [Header("CommunicationValidator v1.2")]
        [SerializeField, Label("動作状況")]
        private string StatusMessage = "";  //Inspector表示用

#if EVMC4U_JA
        [Header("UI オプション")]
#else
        [Header("UI Option")]
#endif
        [SerializeField, Label("画面上に表示する")]
        public bool ShowInformation = false;

#if EVMC4U_JA
        [Header("状態モニタ(表示用)")]
#else
        [Header("Status Monitor(Read only)")]
#endif
        [SerializeField, Label("受信処理再帰呼出し回数")]
        private int CallCountMonitor = 0; //Inspector表示用

        [SerializeField, Label("利用可能")]
        public int Available = 0;
        [SerializeField, Label("送信側Time")]
        public float time = 0;

        [SerializeField, Label("キャリブレーション状態")]
        public CalibrationState calibrationState = 0;
        [SerializeField, Label("キャリブレーションモード")]
        public CalibrationMode calibrationMode = 0;

#if EVMC4U_JA
        [Header("送信側受信状態(表示用)")]
#else
        [Header("Receive Status(Read only)")]
#endif
        [SerializeField, Label("受信許可")]
        public bool ReceiveEnable = false;
        [SerializeField, Label("受信ポート")]
        public int ReceivePort = 0;
        [SerializeField, Label("読み込み済み設定ファイルパス")]
        public string LoadedConfigPath = "";
        [SerializeField, Label("背景色")]
        public Color backgroundColor = Color.clear;

#if EVMC4U_JA
        [Header("送信側ウィンドウ属性情報")]
#else
        [Header("Window Attribute Info(Read only)")]
#endif
        [SerializeField, Label("最前面")]
        public bool IsTopMost = false;
        [SerializeField, Label("透過")]
        public bool IsTransparent = false;
        [SerializeField, Label("クリックスルー")]
        public bool WindowClickThrough = false;
        [SerializeField, Label("枠なし")]
        public bool HideBorder = false;


#if EVMC4U_JA
        [Header("デイジーチェーン")]
#else
        [Header("Daisy Chain")]
#endif
        public GameObject[] NextReceivers = new GameObject[1];

        private ExternalReceiverManager externalReceiverManager = null;
        bool shutdown = false;
        
        readonly Rect rect1 = new Rect(0, 0, 120, 70);
        readonly Rect rect2 = new Rect(10, 20, 100, 30);
        readonly Rect rect3 = new Rect(10, 40, 100, 300);

        void Start()
        {
            externalReceiverManager = new ExternalReceiverManager(NextReceivers);
            StatusMessage = "Waiting for Master...";
        }

        //デイジーチェーンを更新
        public void UpdateDaisyChain()
        {
            externalReceiverManager.GetIExternalReceiver(NextReceivers);
        }

        int GetAvailable()
        {
            return Available;
        }
        
        float GetRemoteTime()
        {
            return time;
        }
        
        void OnGUI()
        {
            if (ShowInformation)
            {
                GUI.TextField(rect1, "ExternalReceiver");
                GUI.Label(rect2, "Available: " + GetAvailable());
                GUI.Label(rect3, "Time: " + GetRemoteTime());
            }
        }
        
        public void MessageDaisyChain(ref uOSC.Message message, int callCount)
        {
            //Startされていない場合無視
            if (externalReceiverManager == null || enabled == false || gameObject.activeInHierarchy == false)
            {
                return;
            }

            if (shutdown)
            {
                return;
            }

            CallCountMonitor = callCount;
            StatusMessage = "OK";

            //異常を検出して動作停止
            try
            {
                ProcessMessage(ref message);
            }
            catch (Exception e)
            {
                StatusMessage = "Error: Exception";
                Debug.LogError(" --- Communication Error ---");
                Debug.LogError(e.ToString());
                shutdown = true;
                return;
            }

            if (!externalReceiverManager.SendNextReceivers(message, callCount))
            {
                StatusMessage = "Infinite loop detected!";
                shutdown = true;
            }
        }

        private void ProcessMessage(ref uOSC.Message message)
        {
            //メッセージアドレスがない、あるいはメッセージがない不正な形式の場合は処理しない
            if (message.address == null || message.values == null)
            {
                StatusMessage = "Bad message.";
                return;
            }

            if (message.address == "/VMC/Ext/OK"
                && (message.values[0] is int))
            {
                Available = (int)message.values[0];
                if (Available == 0)
                {
                    StatusMessage = "Waiting for [Load VRM]";
                }
                else {
                    StatusMessage = "OK";
                }

                //V2.5 キャリブレーション状態(長さ3以上)
                if (message.values.Length >= 3)
                {
                    if ((message.values[1] is int) && (message.values[2] is int))
                    {
                        calibrationState = (CalibrationState)message.values[1];
                        calibrationMode = (CalibrationMode)message.values[2];
                    }
                }
            }
            //データ送信時刻
            else if (message.address == "/VMC/Ext/T"
                && (message.values[0] is float))
            {
                time = (float)message.values[0];
            }
            //V2.4 受信情報
            else if (message.address == "/VMC/Ext/Rcv"
                && (message.values[0] is int)
                && (message.values[1] is int))
            {
                ReceiveEnable = (int)message.values[0] != 0;
                ReceivePort = (int)message.values[1];
            }
            //V2.4 背景色情報
            else if (message.address == "/VMC/Ext/Setting/Color"
                && (message.values[0] is float)
                && (message.values[1] is float)
                && (message.values[2] is float)
                && (message.values[3] is float))
            {
                backgroundColor = new Color((float)message.values[0], (float)message.values[1], (float)message.values[2], (float)message.values[3]);
            }
            //V2.4 ウィンドウ情報
            else if (message.address == "/VMC/Ext/Setting/Win"
                && (message.values[0] is int)
                && (message.values[1] is int)
                && (message.values[2] is int)
                && (message.values[3] is int))
            {
                IsTopMost = (int)message.values[0] != 0;
                IsTransparent = (int)message.values[1] != 0;
                WindowClickThrough = (int)message.values[2] != 0;
                HideBorder = (int)message.values[3] != 0;
            }
            //V2.5 読み込み済み設定ファイルパス情報
            else if (message.address == "/VMC/Ext/Config"
                && (message.values[0] is string))
            {
                LoadedConfigPath = (string)message.values[0];
            }
        }
    }
}