using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Linq;
using System.Text;
using System.Net;
using bbiwarg.Output.DebugOutput;
using bbiwarg.Output.GlassesOutput;
using bbiwarg.Input.InputProviding;
using bbiwarg.Input.InputHandling;
using bbiwarg.TUIO;

namespace bbiwarg
{
    class BBIWARG
    {
        InputProvider inputProvider;
        InputHandler inputHandler;
        TuioCommunicator tuioCommunicator;
        DebugWindow debugWindow;
        GlassesWindow glassesWindow;

        Thread debugOutputThread;
        Thread glassesOutputThread;

        static void Main(string[] args)
        {
            Console.SetWindowSize(Parameters.ConsoleWidth, Parameters.ConsoleHeight);
            handleArgs(args);

            BBIWARG program = new BBIWARG();
            program.run();
        }

        public BBIWARG()
        {
            // inputProvider
            createInputProvider();
            inputProvider.DeviceStartedEvent += handleDeviceStartedEvent;

            // inputHandler
            inputHandler = new InputHandler();
            inputProvider.NewFrameEvent += inputHandler.handleNewFrame;

            // tuioCommunicator
            if (Parameters.TuioEnabled)
            {
                tuioCommunicator = new TuioCommunicator(Parameters.TuioIP.ToString(), Parameters.TuioPort);
                inputHandler.NewProcessedFrameEvent += tuioCommunicator.handleNewFrameData;
            }

            // debug output
            if (Parameters.DebugWindowEnabled)
            {
                debugOutputThread = new Thread(new ThreadStart(debugOutputThreadStart));
            }

            // glasses output
            if (Parameters.GlassesWindowEnabled)
            {
                glassesOutputThread = new Thread(new ThreadStart(glassesOutputThreadStart));
            }

        }

        public void run()
        {
            inputProvider.start();
        }

        private void createInputProvider()
        {
            if (Parameters.InputSource == InputType.Movie)
                inputProvider = new VideoInputProvider(Parameters.InputMoviePath);
            else
                inputProvider = new InputProvider();
        }

        private void debugOutputThreadStart()
        {
            debugWindow = new DebugWindow(inputProvider, inputHandler);
            debugWindow.Run(Parameters.DebugWindowUpdateRate, Parameters.DebugWindowRenderRate);
        }

        private void glassesOutputThreadStart()
        {
            glassesWindow = new GlassesWindow(inputProvider, inputHandler);
            glassesWindow.Run(Parameters.GlassesWindowUpdateRate, Parameters.GlassesWindowRenderRate);
        }

        private void handleDeviceStartedEvent(object sender, EventArgs e)
        {
            startOutputThreads();
        }

        private void startOutputThreads()
        {
            if (Parameters.DebugWindowEnabled)
                debugOutputThread.Start();

            if (Parameters.GlassesWindowEnabled)
                glassesOutputThread.Start();
        }

        private static void handleArgs(String[] args)
        {
            if (args.Length > 0)
            {
                IPAddress ipAddress;
                Int16 port;
                String ipString = null;
                String portString = null;
                if (args.Length == 2)
                {
                    ipString = args[0];
                    portString = args[1];
                }
                else if (args.Length == 1)
                {
                    String[] parts = args[0].Split(':');
                    ipString = parts[0];
                    if (parts.Length == 2)
                        portString = parts[1];
                }

                while (!TuioCommunicator.tryParseIPAddress(ipString, out ipAddress))
                {
                    Console.WriteLine("Please insert the TUIO-Client's IP (Default is 127.0.0.1):");
                    ipString = Console.ReadLine();
                }
                Console.WriteLine("TUIO-IP is set to:" + Parameters.TuioIP.ToString());

                while (!TuioCommunicator.tryParsePort(portString, out port))
                {
                    Console.WriteLine("Please insert the TUIO-Client's Port (Default is 3333):");
                    portString = Console.ReadLine();
                }
                Console.WriteLine("TUIO-PORT is set to:" + Parameters.TuioPort);

                Parameters.setTuioParameters(true, ipAddress, port);
            }
        }
    }
}
