//VERSION 1.0.0

using System;
using System.IO;
using System.Xml;
using System.Linq;
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections.Generic;

/// <summary>Generic tools</summary>
public static class Tools
{
    #region public static utilities

    /// <summary>Smallest allowed number</summary>
    const double EPSILON = 1e-15;

    /// <summary>Returns path to directory for entire solution</summary>
    public static string ExePath
    {
        get
        {
            return System.Windows.Forms.Application.ExecutablePath.Substring(0, System.Windows.Forms.Application.ExecutablePath.LastIndexOf(@"\"));
        }
    }

    /// <summary>Returns path to common data directory for entire solution</summary>
    public static string DataPath
    {
        get
        {
            return ExePath + @"\data";
        }
    }

    #endregion

    #region public classes

    /// <summary>Class for saving settings</summary>
    public class Settings
    {
        private XmlDocument _xmlDoc;
        private XmlNode _settingsNode;
        private string _path;

        public Settings(string path)
        {
            _path = path;
            LoadConfig(path);
        }

        public void LoadConfig(string path)
        {
            //TODO: add error handling
            _xmlDoc = null;
            _xmlDoc = new XmlDocument();
            _xmlDoc.Load(path);
            _settingsNode = _xmlDoc.SelectSingleNode("//appSettings");
        }
        public void Reload()
        {
            LoadConfig(_path);
        }

        public string Path { get { return _path; } }

        public string this[string s]
        {
            get
            {
                LoadConfig(_path);
                XmlNode n = _settingsNode.SelectSingleNode(String.Format("//add[@key='{0}']", s));
                return n != null ? n.Attributes["value"].Value : "";
            }
            set
            {
                LoadConfig(_path);
                XmlNode n = _settingsNode.SelectSingleNode(String.Format("//add[@key='{0}']", s));

                //create the node if it doesn't exist
                if (n == null)
                {
                    n = _xmlDoc.CreateElement("add");
                    _settingsNode.AppendChild(n);
                    XmlAttribute attr = _xmlDoc.CreateAttribute("key");
                    attr.Value = s;
                    n.Attributes.Append(attr);
                    attr = _xmlDoc.CreateAttribute("value");
                    n.Attributes.Append(attr);
                }

                n.Attributes["value"].Value = value;
                _xmlDoc.Save(_path);
            }
        }
    }

    #endregion

    #region extensions

    /// <summary>Save the 2D array to CSV file</summary>
    public static void SaveToFile(this double[,] array, string filepath)
    {
        StreamWriter sw = new StreamWriter(filepath);
        for (int x = 0; x < array.GetLength(0); x++)
        {
            for (int y = 0; y < array.GetLength(1); y++)
                sw.Write(array[x, y] + ",");
            sw.WriteLine();
        }
        sw.Close();
    }

    /// <summary>Load the 2D array from CSV file</summary>
    public static void LoadFromFile(this double[,] array, string filepath)
    {
        StreamReader sr = new StreamReader(filepath);

        int line = 0;
        while (sr.Peek() >= 0)
        {
            string[] values = sr.ReadLine().TrimEnd(',').Split(',');
            for (int i = 0; i < values.Length; i++)
                array[line, i] = double.Parse(values[i]);
            line++;
        }
        sr.Close();
    }

    public static Bitmap GetGrayscale(this Bitmap img)
    {
        //create a copy of img,
        // also fix the problem of indexed pixel format (if any)
        MemoryStream mem = new MemoryStream();
        img.Save(mem, ImageFormat.Jpeg);
        Image imag = Image.FromStream(mem);
        Bitmap imge = new Bitmap(imag);

        //create graphics
        Graphics g = Graphics.FromImage(imge);
        //draw disabled image
        System.Windows.Forms.ControlPaint.DrawImageDisabled(g, img, 0, 0, Color.Transparent);

        //retrun result
        return imge;
    }

    #endregion
}

/// <summary>Solution specific tools</summary>
public static class RoScanTools
{

    #region public enums

    /// <summary>Available scanning modalities</summary>
    public enum ScanModes
    {
        NONE = 0,
        MODEL = 1,
        COLOR = 2,
        THERMO = 4
    }

    #endregion

    #region extensions

    /// <summary>Converts invariant string representation of ScanModes to ScanModes enum</summary>
    public static ScanModes? ToScanModes(this string str)
    {
        ScanModes result = ScanModes.NONE;

        if (str.ToUpperInvariant() == "N") //N cannot be combined with other flags
            return result;

        foreach (char ch in str.ToUpperInvariant())
        {
            if (ch == 'L')
                result |= ScanModes.MODEL;
            else if (ch == 'C')
                result |= ScanModes.COLOR;
            else if (ch == 'T')
                result |= ScanModes.THERMO;
            else
                return null; //contains forbidden character
        }
        return result;
    }

    /// <summary>Converts ScanModes enum to invariant string representation</summary>
    public static string ToStringInvariant(this ScanModes scanmode)
    {
        if (scanmode == ScanModes.NONE)
            return "N";
        else
        {
            string result = string.Empty;
            if (scanmode.HasFlag(ScanModes.MODEL))
                result += "L";
            if (scanmode.HasFlag(ScanModes.COLOR))
                result += "C";
            if (scanmode.HasFlag(ScanModes.THERMO))
                result += "T";
            return result;
        }
    }

    #endregion
}


