﻿using UnityEngine;
using MeshForwardDirection = uDesktopDuplication.Texture.MeshForwardDirection;

public class MultipleMonitorRoundLayouter : MultipleMonitorLayouter
{
    [SerializeField] bool debugDraw = true;

    public float radius = 10f;
    public Vector3 offsetAngle = Vector3.zero;

    void OnDisable()
    {
        foreach (var info in creator_.monitors) {
            info.uddTexture.bend = false;
        }
    }

    protected override void Layout()
    {
        var monitors = creator_.monitors;
        var n = monitors.Count;

        // Keep the local scale z of monitors as 1 to bend them correctly.
        // And save width / height to use same values after reinitialization.
        for (int i = 0; i < n; ++i) {
            var info = monitors[i];
            var savedInfo = creator_.savedInfoList[i];
            var scale = info.gameObject.transform.localScale;
            if (creator_.meshForwardDirection == MeshForwardDirection.Y) {
                scale.y = 1f;
                savedInfo.widthScale = scale.x / info.originalLocalScale.x;
                savedInfo.heightScale = scale.z / info.originalLocalScale.z;
            } else {
                scale.z = 1f;
                savedInfo.widthScale = scale.x / info.originalLocalScale.x;
                savedInfo.heightScale = scale.y / info.originalLocalScale.y;
            }
            info.gameObject.transform.localScale = scale;
        }

        // keep thicness plus value.
        thickness = Mathf.Max(thickness, 0f);

        // calculate total width
        var totalWidth = 0f;
        foreach (var info in monitors) {
            var width = info.gameObject.transform.localScale.x * (info.mesh.bounds.extents.x * 2f);
            totalWidth += width;
        }
        totalWidth += margin * (n - 1);

        // expand radius if total width is larger than the circumference.
        radius = Mathf.Max(radius, (totalWidth + margin) / (2 * Mathf.PI));

        // total angle of monitors
        var totalAngle = totalWidth / radius;

        // layout
        float angle = -totalAngle / 2;
        var offsetRot = Quaternion.Euler(offsetAngle);
        foreach (var info in monitors) {
            var uddTex = info.uddTexture;
            var width = info.gameObject.transform.localScale.x * (info.mesh.bounds.extents.x * 2f);

            angle += (width / radius) * 0.5f;
            var pos = radius * new Vector3(Mathf.Sin(angle), 0f, Mathf.Cos(angle) - 1f);
            pos += radius * Vector3.forward;
            pos = offsetRot * pos;
            pos -= radius * Vector3.forward;
            uddTex.transform.localPosition = pos;
            uddTex.transform.localRotation = offsetRot * Quaternion.AngleAxis(angle * Mathf.Rad2Deg, Vector3.up) * info.originalRotation;
            angle += (width * 0.5f + margin) / radius;

            uddTex.bend = true;
            uddTex.meshForwardDirection = creator_.meshForwardDirection;
            uddTex.radius = radius;
            uddTex.thickness = thickness;
            uddTex.width = uddTex.transform.localScale.x;
        }
    }

    protected override void Update()
    {
        base.Update();
        if (debugDraw) DebugDraw();
    }

    void DebugDraw()
    {
        // draw the circumference in the scene view.
        var scale = transform.localScale.x;
        var center = transform.position - Vector3.forward * radius * scale;
        for (int i = 0; i < 100; ++i) {
            var a0 = 2 * Mathf.PI * i / 100;
            var a1 = 2 * Mathf.PI * (i + 1) / 100;
            var p0 = center + radius * scale * new Vector3(Mathf.Cos(a0), 0f, Mathf.Sin(a0));
            var p1 = center + radius * scale * new Vector3(Mathf.Cos(a1), 0f, Mathf.Sin(a1));
            Debug.DrawLine(p0, p1, Color.red);
        }
    }
}

