using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static CommunicationEvents;

public class LotTool : Gadget
    //constructs a Perpendicular between a Line and a Point
{
    //Variables for LineMode distinction
    private bool LotModeIsPointSelected = false;
    private bool LotModeIsLineSelected = false;
    private AbstractLineFact LotModeLineSelected = null;
    private PointFact LotModeIntersectionPoint = null;
    private PointFact LotModeLinePointA = null;
    private RaycastHit LotModeLineHit;

    //Attributes for simulating the drawing of a line
    private bool lineDrawingActivated;
    public WorldCursor Cursor;
    public LineRenderer lineRenderer;
    private List<Vector3> linePositions = new List<Vector3>();
    public Material linePreviewMaterial;

    void Awake()
    {
        if (FactManager == null)
            FactManager = GameObject.FindObjectOfType<FactManager>();

        if (this.Cursor == null)
            this.Cursor = GameObject.FindObjectOfType<WorldCursor>();

        this.UiName = "Lot Mode";
        CommunicationEvents.TriggerEvent.AddListener(OnHit);
    }

    //Initialize Gadget when enabled AND activated
    void OnEnable()
    {
        this.Cursor.setLayerMask(~this.ignoreLayerMask.value);
        this.ResetGadget();
    }

    void OnDisable()
    {
        this.ResetGadget();
    }

    public override void OnHit(RaycastHit hit)
    {
        void CreateRayAndAngles(string pidIntersectionPoint, string pidLotPoint, bool samestep)
        {
            FactManager.AddRayFact(pidIntersectionPoint, pidLotPoint, samestep);

            //TODO: create at all? / for all points on basline?
            FactManager.AddAngleFact(
                this.LotModeLineSelected.Pid1 == pidIntersectionPoint ? this.LotModeLineSelected.Pid2 : this.LotModeLineSelected.Pid1,
                pidIntersectionPoint, pidLotPoint, true);
        }

        if (!this.isActiveAndEnabled) return;

        //If LotPoint is on baseLine
        if (this.LotModeIsPointSelected && (hit.transform.gameObject.layer == LayerMask.NameToLayer("Default") || hit.transform.gameObject.layer == LayerMask.NameToLayer("Tree")))
        {
            Vector3 LotPoint = Math3d.ProjectPointOnLine(hit.point, this.LotModeLineSelected.Dir, this.LotModeIntersectionPoint.Point);

            //TODO: which normal?
            CreateRayAndAngles(this.LotModeIntersectionPoint.Id, FactManager.AddPointFact(LotPoint, hit.normal).Id, true);
            this.ResetGadget();
        }

        //If baseline already selected and point selected
        else if (this.LotModeIsLineSelected && !this.LotModeIsPointSelected && hit.transform.gameObject.layer == LayerMask.NameToLayer("Point"))
        {
            PointFact tempFact = LevelFacts[hit.transform.GetComponent<FactObject>().URI] as PointFact;

            Vector3 intersectionPoint = Math3d.ProjectPointOnLine(this.LotModeLinePointA.Point, this.LotModeLineSelected.Dir, tempFact.Point);

            if (intersectionPoint == tempFact.Point) // Vector3.operator== tests for almost Equal()
            {   //TempFact is on baseLine
                this.LotModeIsPointSelected = true;
                this.LotModeIntersectionPoint = tempFact;
                return;
            }

            //TODO: test Facts existance
            //add Facts
            var intersectionId = FactManager.AddPointFact(intersectionPoint, this.LotModeLineHit.normal).Id;

            if(this.LotModeLineSelected is RayFact) //Add OnLineFact only on Ray not Line
                FactManager.AddOnLineFact(intersectionId, this.LotModeLineSelected.Id, true);

            CreateRayAndAngles(intersectionId, tempFact.Id, true);
            this.ResetGadget();
        }

        //If nothing yet selected
        else if (!this.LotModeIsLineSelected
            && (hit.transform.gameObject.layer == LayerMask.NameToLayer("Ray")
            || hit.transform.gameObject.layer == LayerMask.NameToLayer("Line")))
        {
            Fact tempFact = LevelFacts[hit.transform.GetComponent<FactObject>().URI];

            //Activate LineDrawing for preview
            this.LotModeIsLineSelected = true;
            this.LotModeLineSelected = tempFact as AbstractLineFact;
            this.LotModeLinePointA = (PointFact) LevelFacts[this.LotModeLineSelected.Pid1];
            this.LotModeLineHit = hit;
            this.ActivateLineDrawing();
        }

        //unexpected usage
        else
        {
            if (this.LotModeIsLineSelected)
            {
                //Deactivate LineDrawing and first point selection
                this.ResetGadget();
            }
        }
    }

    void Update()
    {
        if (!this.isActiveAndEnabled)
            return;
        if (this.lineDrawingActivated)
            UpdateLineDrawing();
    }

    private void ResetGadget()
    {
        this.LotModeIsLineSelected = false;
        this.LotModeLineSelected = null;

        this.LotModeLinePointA = null;

        this.LotModeIsPointSelected = false;
        this.LotModeIntersectionPoint = null;
        //TODO? reset?
        //this.LotModeLineHit;
        DeactivateLineDrawing();
    }

    private void ActivateLineDrawing()
    {
        this.lineRenderer.positionCount = 3;
        this.lineRenderer.material = this.linePreviewMaterial;

        lineRenderer.startWidth = 0.095f;
        lineRenderer.endWidth = 0.095f;
        //Set LineDrawing activated
        this.lineDrawingActivated = true;

        //start at curser
        linePositions.Add(this.Cursor.transform.position);
        //Project curser perpendicular on Line for intersection-point
        linePositions.Add(Math3d.ProjectPointOnLine(this.LotModeLinePointA.Point, this.LotModeLineSelected.Dir, this.linePositions[0]));
        //end at Point on the line (i.c.o. projection beeing outside a finite line)
        linePositions.Add(Math3d.ProjectPointOnLine(this.LotModeLinePointA.Point, this.LotModeLineSelected.Dir, this.LotModeLineHit.point));

        this.lineRenderer.SetPosition(0, linePositions[0]);
        this.lineRenderer.SetPosition(1, linePositions[1]);
        this.lineRenderer.SetPosition(2, linePositions[2]);

    }

    //Updates the points of the Lines when baseLine was selected in LineMode
    private void UpdateLineDrawing()
    {
        if (this.LotModeIsPointSelected)
        {
            this.linePositions[1] = this.LotModeIntersectionPoint.Point;
            this.linePositions[0] = Math3d.ProjectPointOnLine(this.Cursor.transform.position, this.LotModeLineSelected.Dir, this.linePositions[1]);
        }
        else
        {
            this.linePositions[0] = this.Cursor.transform.position;
            this.linePositions[1] = Math3d.ProjectPointOnLine(this.LotModeLinePointA.Point, this.LotModeLineSelected.Dir, this.linePositions[0]);
        }

        this.lineRenderer.SetPosition(0, this.linePositions[0]);
        this.lineRenderer.SetPosition(1, this.linePositions[1]);
    }

    //Deactivate LineDrawing so that no Line gets drawn when Cursor changes
    private void DeactivateLineDrawing()
    {
        this.lineRenderer.positionCount = 0;
        this.linePositions = new List<Vector3>();
        this.lineDrawingActivated = false;
    }
}