using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using GME;

namespace GME.CSharp
{
    /// <summary>
    /// Automatically redirects console messages to the GME console output, if GME is available.
    /// Otherwise prints the output to System console.
    /// </summary>
    public class GMEConsole
    {

        /// <summary>
        /// The GME application variable
        /// </summary>
        public IGMEOLEApp gme = null;
        private GMETextWriter error;
        private GMETextWriter warning;
        private GMETextWriter info;
        private GMETextWriter normal;

        public GMEConsole()
        {
            error = new GMETextWriter(msgtype_enum.MSG_ERROR, this);
            warning = new GMETextWriter(msgtype_enum.MSG_WARNING, this);
            info = new GMETextWriter(msgtype_enum.MSG_INFO, this);
            normal = new GMETextWriter(msgtype_enum.MSG_NORMAL, this);
        }

        /// <summary>
        /// Handles error messages
        /// The message to be written. GME Console does not handle special characters and trims white-spaces.
        /// Example: GMEConsole.Error.Write("RootFolder name error: {0}.", rf.Name);
        /// If console is initialized, the message appears in GME console, if not, then in standard error.
        /// If DEBUG is defined, it also appears in VS output window.
        /// </summary>
        public TextWriter Error
        {
            get { return error; }
        }

        /// <summary>
        /// Prints messages.
        /// The message to be written. GME Console does not handle special characters and trims white-spaces.
        /// Example: GMEConsole.Out.Write("RootFolder name : {0}.", rf.Name);
        /// </summary>
        public TextWriter Out
        {
            get { return normal; }
        }


        /// <summary>
        /// Prints warning messages.
        /// The message to be written. GME Console does not handle special characters and trims white-spaces.
        /// Example: GMEConsole.Warning.Write("RootFolder name is not changed : {0}.", rf.Name);
        /// </summary>
        public TextWriter Warning
        {
            get { return warning; }
        }


        /// <summary>
        /// Proints info messages.
        /// The message to be written. GME Console does not handle special characters and trims white-spaces.
        /// Example: GMEConsole.Info.Write("RootFolder name is changed : {0}.", rf.Name);
        /// </summary>
        public TextWriter Info
        {
            get { return info; }
        }

        /// <summary>
        /// Clear the console
        /// </summary>
        public void Clear()
        {
            if (gme != null)
                gme.ConsoleClear();
            else
                System.Console.Clear();
        }


        public static GMEConsole CreateFromProject(GME.MGA.MgaProject project)
        {
            GMEConsole console = new GMEConsole();
            try
            {
                // Initializing console               
                console.gme = (IGMEOLEApp)project.GetClientByName("GME.Application").OLEServer;
            }
            catch (System.Runtime.InteropServices.COMException ex)
            {
                // if GME is not present, the interpreter is called from standalone test application
                if (ex.ErrorCode != -2023423888) // HResult 0x87650070: "Search by name failed"
                {
                    throw;
                }
                console.gme = null;
            }
            return console;
        }
    }


    public class GMETextWriter : System.IO.TextWriter
    {
        private msgtype_enum type;
        private GMEConsole console;

        public GMETextWriter(msgtype_enum type, GMEConsole console)
        {
            this.type = type;
            this.console = console;
        }

        override public Encoding Encoding
        {
            get { return Encoding.Unicode; }
        }

        override public void WriteLine(string str)
        {
            Write(str + Environment.NewLine);
        }

        override public void Write(string str)
        {
            if (console.gme == null)
            {
                switch (type)
                {
                    case msgtype_enum.MSG_NORMAL:
                        Console.Out.Write(str);
                        break;
                    case msgtype_enum.MSG_INFO:
                        Console.Out.Write("Information: " + str);
                        break;
                    case msgtype_enum.MSG_WARNING:
                        Console.Out.Write("Warning: " + str);
                        break;
                    case msgtype_enum.MSG_ERROR:
                        Console.Error.Write(str);
#if(DEBUG)
                        System.Diagnostics.Debug.Write(str);
#endif
                        break;
                }
            }
            else
            {
                console.gme.ConsoleMessage(str, type);
            }
        }
    }
}
