using Microscopic_Traffic_Simulator.Renderers;
using Microscopic_Traffic_Simulator.ViewModels;
using Microscopic_Traffic_Simulator___Model.GeometricObjects.Lanes;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace Microscopic_Traffic_Simulator.Views.MainWindowView
{
    /// <summary>
    /// Interaction logic for CanvasUserControl.xaml
    /// </summary>
    public partial class CanvasUserControl : UserControl
    {
        /// <summary>
        /// Renderer for geometric topology.
        /// </summary>
        private TopologyRenderer topologyRenderer;
        /// <summary>
        /// Renderer for geometric topology.
        /// </summary>
        internal TopologyRenderer TopologyRenderer { get { return topologyRenderer; } }

        /// <summary>
        /// Renderer for simulation traffic.
        /// </summary>
        private SimulationTrafficRenderer simulationTrafficRenderer;
        /// <summary>
        /// Renderer for simulation traffic.
        /// </summary>
        internal SimulationTrafficRenderer SimulationTrafficRenderer { get { return simulationTrafficRenderer; } }

        /// <summary>
        /// Canvas for rendering preview of straight road lane.
        /// </summary>
        private LaneBuildingRenderer straightLaneBuildingRenderer;
        /// <summary>
        /// Canvas for rendering preview of straight road lane.
        /// </summary>
        internal LaneBuildingRenderer StraightLaneBuildingRenderer
        {
            get { return straightLaneBuildingRenderer; }
        }

        /// <summary>
        /// Canvas for rendering preview of bezier road lane.
        /// </summary>
        private BezierLaneBuildingRenderer bezierLaneBuildingRenderer;
        /// <summary>
        /// Canvas for rendering preview of bezier road lane.
        /// </summary>
        internal BezierLaneBuildingRenderer BezierLaneBuildingRenderer { get { return bezierLaneBuildingRenderer; } }

        /// <summary>
        /// Reference to canvas view model stored as data context.
        /// </summary>
        private CanvasViewModel CanvasViewModel { get { return DataContext as CanvasViewModel; } }

        /// <summary>
        /// Reference to canvas mover.
        /// </summary>
        private CanvasMover mover;
        /// <summary>
        /// Reference to canvas mover.
        /// </summary>
        internal CanvasMover Mover { get { return mover; } }

        /// <summary>
        /// Reference to canvas zoomer.
        /// </summary>
        private CanvasZoomer zoomer;
        /// <summary>
        /// Reference to canvas zoomer.
        /// </summary>
        internal CanvasZoomer Zoomer { get { return zoomer; } }

        /// <summary>
        /// Reference to road previewer.
        /// </summary>
        private CanvasRoadPreviewer roadPreviewer;
        /// <summary>
        /// Reference to road previewer.
        /// </summary>
        internal CanvasRoadPreviewer RoadPreviewer { get { return roadPreviewer; } }

        /// <summary>
        /// Reference renderer of generator possible locations.
        /// </summary>
        private GeneratorPossibleLocationsRenderer generatorPossibleLocationsRenderer;
        /// <summary>
        /// Reference renderer of generator possible locations.
        /// </summary>
        internal GeneratorPossibleLocationsRenderer GeneratorPossibleLocationsRenderer 
        {
            get { return generatorPossibleLocationsRenderer; } 
        }

        /// <summary>
        /// Initialize canvas control.
        /// </summary>
        public CanvasUserControl()
        {
            InitializeComponent();
            List<VisualCanvasRenderer> renderers = new List<VisualCanvasRenderer>();
            topologyRenderer = new TopologyRenderer(topologyCanvas.CreateNewVisual());
            renderers.Add(topologyRenderer);
            simulationTrafficRenderer = new SimulationTrafficRenderer(topologyCanvas.CreateNewVisual());
            renderers.Add(simulationTrafficRenderer);
            straightLaneBuildingRenderer = new LaneBuildingRenderer(topologyCanvas.CreateNewVisual());
            renderers.Add(straightLaneBuildingRenderer);
            bezierLaneBuildingRenderer = new BezierLaneBuildingRenderer(topologyCanvas.CreateNewVisual());
            renderers.Add(bezierLaneBuildingRenderer);
            generatorPossibleLocationsRenderer = new GeneratorPossibleLocationsRenderer(
                topologyCanvas.CreateNewVisual());
            renderers.Add(generatorPossibleLocationsRenderer);
            mover = new CanvasMover(renderers);
            zoomer = new CanvasZoomer(renderers);
            roadPreviewer = new CanvasRoadPreviewer(new Dictionary<LaneType, LaneBuildingRenderer>
            {
                { LaneType.Straight, straightLaneBuildingRenderer },
                { LaneType.Bezier, bezierLaneBuildingRenderer }
            }, topologyRenderer);
        }

        /// <summary>
        /// Initialize renderers. Render geometric topology after loading of control.
        /// </summary>
        /// <param name="sender">Sender object.</param>
        /// <param name="e">Unused event args.</param>
        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            if (!DesignerProperties.GetIsInDesignMode(this))
            {
                roadPreviewer.SetCanvasViewModel(CanvasViewModel);
                roadPreviewer.LaneTypeWasChanged();
                generatorPossibleLocationsRenderer.Lanes = CanvasViewModel.GeometricTopology.Lanes;
                Window.GetWindow(this).KeyDown += CanvasUserControl_KeyDown;
                topologyRenderer.GeometricTopology = CanvasViewModel.GeometricTopology;
                topologyRenderer.RenderTopology();
            }
        }

        /// <summary>
        /// Serves keys on keyboard pressed down.
        /// </summary>
        /// <param name="sender">Sender object.</param>
        /// <param name="e">Key event args containing information which key was pressed.</param>
        private void CanvasUserControl_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Escape)
            {
                roadPreviewer.ClearPreviewOfBuildingOfAnyRoads();
            }
        }

        /// <summary>
        /// Event handler for catching releasing mouse left button.
        /// </summary>
        /// <param name="sender">Not used sender reference.</param>
        /// <param name="e">Event args with mouse location.</param>
        private void topologyCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (CanvasViewModel.BuildingMode == BuildingMode.Lane)
            {
                roadPreviewer.MouseLeftButtonUp(e.GetPosition(topologyCanvas));
            }
            else if (CanvasViewModel.BuildingMode == BuildingMode.Generator)
            {
                Lane laneWhereGeneratorToAdd = generatorPossibleLocationsRenderer.MouseLeftButtonUp();
                if (laneWhereGeneratorToAdd != null)
                {
                    CanvasViewModel.CreateGeneratorForLane(laneWhereGeneratorToAdd);
                    topologyRenderer.RenderTopology();
                    generatorPossibleLocationsRenderer.MouseMove(e.GetPosition(topologyCanvas));
                }
            }
        }

        /// <summary>
        /// Event handler for catching pressing mouse left button.
        /// </summary>
        /// <param name="sender">Not used sender reference.</param>
        /// <param name="e">Event args with mouse location.</param>
        private void topologyCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (CanvasViewModel.BuildingMode == BuildingMode.Lane)
            {
                roadPreviewer.MouseLeftButtonDown(e.GetPosition(topologyCanvas));
            }
        }

        /// <summary>
        /// Event handler for move of the mouse.
        /// </summary>
        /// <param name="sender">Not used sender reference.</param>
        /// <param name="e">Mouse event args.</param>
        private void topologyCanvas_MouseMove(object sender, MouseEventArgs e)
        {
            Point currentMouseLocationOnCanvas = e.GetPosition(topologyCanvas);

            if (e.RightButton == MouseButtonState.Pressed)
            {
                mover.SetLastMousePositionToRenderersForMovingCanvas(currentMouseLocationOnCanvas);
            }
            else if (e.LeftButton == MouseButtonState.Pressed)
            {
                if (CanvasViewModel.BuildingMode == BuildingMode.Lane)
                {
                    roadPreviewer.MovePointOfLaneIfCursorIsNear(currentMouseLocationOnCanvas);
                }
            }
            else
            {
                mover.ResetLastMousePositionToRenderersForMovingCanvas();
                if (CanvasViewModel.BuildingMode == BuildingMode.Lane)
                {
                    roadPreviewer.RenderBuildingLane(currentMouseLocationOnCanvas);
                }
                else if (CanvasViewModel.BuildingMode == BuildingMode.Generator)
                {
                    generatorPossibleLocationsRenderer.MouseMove(currentMouseLocationOnCanvas);
                }
            }            
        }

        /// <summary>
        /// Event handler for moving of mouse wheel which is used to change the zoom.
        /// </summary>
        /// <param name="sender">Not used sender reference.</param>
        /// <param name="e">Mouse wheel event args used for determining direction of mouse wheel move.</param>
        private void topologyCanvas_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            Slider zoomSlider = (Window.GetWindow(this) as MainWindow).bottomPanelUserControl.zoomSlider;
            zoomer.SetCurrentCursorPositionAsZoomPoint(e.GetPosition(topologyCanvas));
            if (e.Delta > 0)
                zoomSlider.Value++;
            else
                zoomSlider.Value--;
        }

        /// <summary>
        /// Event handler for pressing of a key.
        /// </summary>
        /// <param name="sender">Not used sender reference.</param>
        /// <param name="e">Event args containing information which key was pressed.</param>        
        private void topologyCanvas_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Escape)
            {
                roadPreviewer.ClearPreviewOfBuildingOfAnyRoads();
            }
        }

        /// <summary>
        /// Event handler for pressing right mouse button down.
        /// </summary>
        /// <param name="sender">Not used sender reference.</param>
        /// <param name="e">Event args containing information about location of the cursor.</param>
        private void topologyCanvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            mover.SetLastMousePositionToRenderersForMovingCanvas(e.GetPosition(topologyCanvas));
        }
    }
}
