...1-
...2|
...3|
...4|
...5|
...6|
...7|
...8|
...9|
..10|
..11|
..12|
..13|
..14|
..15|
..16|
..17|
..18|
..19|
..20-

..21
..22-
..23|
..24|
..25|
..26|
..27|
..28|
..29|
..30|
..31-

..32
..33
..34
..35
..36
..37-
..38|
..39|
..40|
..41|
..42|
..43|
..44|
..45-

..46
..47-
..48|
..49|
..50|-
..51||
..52||
..53||
..54|-

..55|
..56|
..57|
..58|
..59|-
..60||
..61||
..62||
..63||
..64||
..65||
..66||
..67||
..68||
..69||
..70||
..71||
..72||
..73||
..74||
..75||
..76|-

..77|
..78|-
..79||
..80||
..81||
..82||
..83||
..84||
..85||
..86||
..87||
..88||
..89||
..90||
..91|-

..92|
..93|-
..94||
..95||
..96||
..97||
..98||
..99||
.100||
.101||
.102||
.103||
.104||
.105||
.106||
.107||
.108||
.109||
.110||
.111||
.112||
.113||
.114||
.115||
.116||
.117||-
.118|||
.119|||
.120|||
.121|||
.122|||
.123|||
.124|||
.125|||
.126|||
.127|||
.128|||
.129|||
.130|||
.131|||
.132|||
.133|||
.134|||
.135||-

.136||
.137||
.138||
.139||
.140||-
.141|||
.142||-

.143||
.144||-
.145|||
.146|||
.147||-

.148||
.149||
.150||
.151||
.152||
.153||
.154||
.155||
.156||
.157||
.158|-

.159|
.160|-
.161||
.162||
.163||
.164||
.165||
.166||
.167||
.168||
.169||
.170||
.171||
.172||
.173||
.174||
.175||
.176||
.177||
.178||
.179||
.180||
.181||
.182||
.183||
.184||
.185||
.186||
.187||
.188||
.189||
.190||
.191|-

.192|
.193|
.194|-
.195||
.196||
.197||
.198||
.199||
.200||
.201||
.202||
.203||
.204||
.205||
.206|-

.207|
.208|-
.209||
.210||
.211||
.212||-
.213|||
.214|||
.215|||
.216|||
.217|||
.218|||
.219|||
.220|||
.221|||
.222|||
.223|||
.224||-

.225||
.226||-
.227|||
.228|||
.229|||
.230|||
.231|||
.232|||
.233|||
.234|||
.235|||
.236|||
.237|||
.238|||
.239|||
.240|||
.241|||
.242|||
.243|||
.244|||
.245|||
.246|||
.247|||
.248|||
.249|||
.250|||
.251|||
.252|||
.253|||
.254|||
.255|||
.256||-

.257||
.258||-
.259|||
.260|||
.261|||
.262|||
.263|||
.264|||
.265|||
.266|||
.267|||
.268|||
.269|||
.270||-

.271||
.272||-
.273|||
.274|||
.275||-

.276||
.277||
.278||-
.279|||
.280|||
.281|||
.282|||
.283|||
.284|||
.285|||
.286|||
.287|||
.288|||
.289|||
.290|||
.291|||
.292|||
.293|||
.294|||
.295|||
.296|||
.297|||
.298|||
.299|||
.300|||
.301|||
.302|||-
.303||||
.304||||
.305||||
.306||||
.307||||
.308||||
.309||||
.310||||
.311||||
.312||||
.313||||
.314||||
.315||||
.316||||
.317||||
.318||||
.319||||
.320||||
.321||||
.322||||
.323||||
.324||||
.325||||
.326||||
.327||||
.328||||
.329||||
.330||||
.331||||
.332||||
.333||||
.334||||
.335||||
.336||||
.337||||
.338||||
.339||||
.340||||
.341||||
.342||||
.343||||
.344||||
.345|||-

.346|||
.347|||
.348||-

.349||
.350||-
.351|||-
.352||||
.353||||
.354||||
.355||||
.356||||
.357||||
.358||||
.359||||
.360||||
.361||||
.362||||
.363||||
.364||||
.365||||
.366||||
.367||||
.368||||
.369||||
.370||||
.371||||
.372||||
.373||||
.374||||
.375||||
.376||||
.377||||
.378||||
.379||||
.380||||
.381||||
.382||||
.383||||
.384||||
.385||||
.386||||
.387||||
.388||||
.389||||
.390||||
.391||||
.392||||
.393||||
.394||||
.395||||
.396||||
.397||||
.398||||
.399||||
.400||||
.401||||
.402|||-

.403|||
.404|||
.405|||
.406|||
.407|||
.408|||
.409|||
.410|||
.411|||
.412|||
.413|||
.414|||
.415|||
.416|||
.417|||
.418|||
.419|||
.420|||
.421|||
.422|||
.423|||
.424|||
.425|||
.426||-

.427||
.428|-

.429-

.430
.431
/* CharMY.CodeToHtml SettingToCssConverter
 * 
 * COPYLEFT (C) CharMY 2012-2013 Yanagihara Masami
 * 
 * 
 * This program is free software: you can redistribute it and/or modify   *
 * it under the terms of the GNU General Public License as published by   *
 * the Free Software Foundation, either version 3 of the License, or      *
 * (at your option) any later version.                                    *
 *                                                                        *
 * This program is distributed in the hope that it will be useful,        *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of         *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
 * GNU General Public License for more details.                           *
 *                                                                        *
 * You should have received a copy of the GNU General Public License      *
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
 * 
 * 
 */


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using CharMY.ComponentModel;
using CharMY.IO;
using CharMY.Text;
using CharMY.Xml;


namespace CharMY.CodeToHtml
{
    [Flags]
    public enum VSEditorVersion
    {
        VS2010ExpressCSharp = 0x0,
        VS2012ExpressDesktop = 0x1,
        VSVersion = VS2010ExpressCSharp | VS2012ExpressDesktop,

        White = 0x0,
        Black = 0x10,
        ColorVersion = White | Black,
    
}
    public class SettingToCssConverter : CharMYCore.NonElement
    {
        private readonly VSEditorVersion _version;
        public SettingToCssConverter(string classNameVSEditorVersion version)
        {
            Checker.ArgumentNotNull(className);
            _class_name = className;
            _version = version;
        
}

        public override string ToString() { return "css ver " + _version; }

        private FileInfo DefaultSettingFile
        {
            get
            {
                switch (_version & VSEditorVersion.VSVersion)
                {
                    case VSEditorVersion.VS2010ExpressCSharp:
                        return
                            Files.DeskTop.GetRelativeFile(__2010_setting_from_desktop)
                            ?? Files.DeskTop.GetRelativeFile(__2012_setting_from_desktop);

                    case VSEditorVersion.VS2012ExpressDesktop:
                    default:
                        return
                            Files.DeskTop.GetRelativeFile(__2012_setting_from_desktop)
                            ?? Files.DeskTop.GetRelativeFile(__2010_setting_from_desktop);
                }
            }
        
}
        private string DefaultColorFileName
        {
            get
            {
                switch (_version & VSEditorVersion.ColorVersion)
                {
                    case VSEditorVersion.White:
                        return @"default-white-array.xml";

                    case VSEditorVersion.Black:
                    default:
                        return @"default-black-array.xml";
                }
            }
        
}

        #region fields & properties

        public string ClassName { get { return _class_name; } }
        public string ClassNameCode { get { return _class_name + "-code"; } }
        public string ClassNameLineNumber { get { return _class_name + "-line"; } }
        private string _class_name;

        private int
            _line_number = 0,
            _line_background = 0,
            _line_separator = 0,
            _line_square = 0,
            _foreground = 0,
            _background = 0xFFFFFF;
        public string ColorCodeLineNumber { get { return ColorCode(_line_number); } }
        public string ColorCodeLineBackground { get { return ColorCode(_line_background); } }
        public string ColorCodeLineSeparator { get { return ColorCode(_line_separator); } }
        public string ColorCodeLineSquare { get { return ColorCode(_line_square); } }
        public string ColorCodeForeground { get { return ColorCode(_foreground); } }
        public string ColorCodeBackground { get { return ColorCode(_background); } }
        public string ColorCodeCollapsedForeground { get { return ColorCode(ColorEdit(_foreground0x8080801)); } }
        public string ColorCodeCollapsedBackground { get { return ColorCode(ColorEdit(_background0x8080807)); } }
        public static string ColorCode(int color) { return "#" + color.ToString("X6"); }
        private static int ColorEdit(int fromint toint level)
        {
            int _01 = from & 0xFF;
            int _02 = (from >> 0x8& 0xFF;
            int _03 = (from >> 0x10& 0xFF;

            int _11 = to & 0xFF;
            int _12 = (to >> 0x8& 0xFF;
            int _13 = (to >> 0x10& 0xFF;

            int _21 = (_01 * level + _11/ (level + 1);
            int _22 = (_02 * level + _12/ (level + 1);
            int _23 = (_03 * level + _13/ (level + 1);

            var result =
                (_21 & 0xFF)
                | ((_22 & 0xFF<< 0x8)
                | ((_23 & 0xFF<< 0x10);
            return result;
        
}

        private readonly IDictionary<intstring> _colors = new Dictionary<intstring>();

        public string ColorClass(int rint gint b)
        {
            return this.ColorClass(ToColorKey(rgb));
        
}
        public string ColorClass(int key)
        {
            var result = _colors.ElementAtOrDefault(keyUndefinedName + key.ToString("X6"));
            return result;
        
}
        public const string UndefinedName = "UndefinedColor";

        public Encoding Encoding { get { return __encoding; } }
        public string NameOfSpace { get { return __space_name; } }
        public string NameOfDefault { get { return __default_name; } }
        public string NameOfLineNumber { get { return (_version & VSEditorVersion.VSVersion== VSEditorVersion.VS2012ExpressDesktop ? __linenum_name_2012 : __linenum_name; } }
        public string NameOfLineSeparator { get { return __linespr_name; } }
        public string NameOfLineCollapse { get { return __linesqr_name; } }
        public string NameOfLineCollapseEnd { get { return __linesqr_end_name; } }

        
#endregion

        #region static fields

        private const string
            __2010_setting_from_desktop = @"../Documents/Visual Studio 2010/Settings/C# Express/CurrentSettings.vssettings",
            __2012_setting_from_desktop = @"../Documents/Visual Studio 2012/Settings/WD Express/CurrentSettings.vssettings";

        private static readonly Encoding __encoding = Encoding.UTF8;
        private static readonly NumberFormat __hex_format = NumberFormats.Hex();
        internal const string
            __collapsed_name = "CollapsibleTextCollapsed",
            __linesqr_name = "outlining_square",
            __linesqr_end_name = "outlining_square_end",
            __link_names = "Keyword|UserTypes|UserTypesInterfaces|UserTypesValuetypes|UserTypesEnums|UserTypesDelegates|UserTypesTypeparameters";
        private const string
            __space_name = "WideSpace",
            __default_name = "PlainText",
            __linenum_name = "LineNumbers",
            __linenum_name_2012 = "LineNumber",
            __linespr_name = "outlining_collapsehintadornment";
        private const string
            __key_name = "Name",
            __key_foreground = "Foreground",
            __key_background = "Background",
            __key_editor_item_name = "Item",
            __key_editor_id_name = "Category",
            __key_editor_id = "GUID",
            __key_editor_id_2010 = "{A27B4E24-A735-4D1D-B8E7-9716E1E3D8E0}",
            __key_editor_id_2012_0 = "{58E96763-1D3B-4E05-B6BA-FF7115FD0B7B}",
            __key_editor_id_2012_1 = "{75A05685-00A8-4DED-BAE5-E7A50BFA929A}",
            __key_editor_id_2012_2 = "{E0187991-B458-4F7E-8CA9-42C9A573B56C}";

        
#endregion

        public string MakeCss(FileInfo setting = null)
        {
            setting = setting ?? this.DefaultSettingFile;
            if (!this.LoadSettingFile(setting))
                return null;

#if WRITE_INFO
            foreach (var pair in _colors)
                Console.WriteLine(pair.Key.ToString(__hex_format) + " < " + pair.Value);
#endif

            return this.MakeCssCore()
                .ToSingleStringLines();
        
}

        #region css factory

        [Serializable]
        public struct ColoringItem
        {
            public int Background;
            public int Foreground;
            public string Name;

            public override string ToString()
            {
                var result = Name ?? "";
                if (Foreground >= 0)
                    result += ":" + Foreground.ToString("X6");
                return result;
            }
        
}
        public static IEnumerable<ColoringItem> GetItems(FileInfo file)
        {
            if (file == null || !file.Exists)
                return Enumerable.Empty<ColoringItem>();

            var result = XmlChain.LoadDocument(file)
                .GetChildNodes()
                .Where(node => node.Name == __key_editor_id_name
                    && (node.GetAttribute(__key_editor_id== __key_editor_id_2012_0
                        || node.GetAttribute(__key_editor_id== __key_editor_id_2012_1
                        || node.GetAttribute(__key_editor_id== __key_editor_id_2012_2)
                )
                .SelectMany(nodec => nodec.GetChildNodes())
                .Where(node => node.NodeType != XmlNodeType.Whitespace
                    && node.Name == __key_editor_item_name)
                .Select(chain => new ColoringItem()
                {
                    Foreground = ToColorKey(chain.GetAttribute(__key_foreground)),
                    Background = ToColorKey(chain.GetAttribute(__key_background)),
                    Name = chain
                        .GetAttribute(__key_name)
                        .Replace(" """)
                        .Replace("(""")
                        .Replace(")""")
                        .Replace(".""_")
                        .Replace("/""_")
                        .Replace("+""_p")
                        .Replace("@""At")
                        .Replace("#""Sharp")
                });
            return result;
        
}
        public static int ToColorKey(string text)
        {
            if (text == null)
                return -1;

            var hex = text.Replace("0x""").To(0__hex_format);
            int special = (hex & 0x7F000000);
            if (special > 0)
                return -(special >> 0x18);
            int r = (hex & 0xFF);
            int g = (hex & 0xFF00>> 0x8;
            int b = (hex & 0xFF0000>> 0x10;
            return ToColorKey(rgb);
        
}
        public static int ToColorKey(int rint gint b)
        {
            var result = (r << 0x10| (g << 0x8| b;
            return result;
        
}

        private bool LoadSettingFile(FileInfo setting)
        {
            if (setting == null)
                return false;

            IEnumerable<ColoringItem> default_list;
            var io = Files.SerialXml<ColoringItem[]>();
            var dir = @"./";
#if DEBUG
            dir = @"../../_/";
#endif
            default_list = io.Load(Files.ExeFile.Directory.GetRelativeFile(dir + this.DefaultColorFileName), null);
            Checker.StateTrue(default_list != null);

            _line_number = -1;
            _line_background = -1;
            _line_separator = -1;
            _foreground = -1;
            _background = -1;

            var items = GetItems(setting).ToArray();
            default_list = (default_list ?? default_list.ToEmpty())
                .Where(add => !items.Where(item => item.Name == add.Name).Any())
                .ToArray();

            #region Update _colors

            _colors.Clear();
            foreach (var item in items.Concat(default_list))
            {
                if (item.Name == __default_name)
                {
                    _foreground = item.Foreground;
                    if (item.Background >= 0)
                        _background = item.Background;
                }
                else if (item.Name == __linenum_name || item.Name == __linenum_name_2012)
                {
                    _line_number = item.Foreground;
                    if (item.Background >= 0)
                        _line_background = item.Background;
                }
                else if (item.Name == __linespr_name)
                {
                    _line_separator = item.Foreground;
                }
                else if (item.Name == __linesqr_name)
                {
                    _line_square = item.Foreground;
                }
                else if (!_colors.ContainsKey(item.Foreground|| item.Name.Length < _colors[item.Foreground].Length)
                {
                    _colors[item.Foreground= item.Name;
                }
            }

            if (_line_number < 0)
                _line_number = _foreground;
            if (_line_separator < 0)
                _line_separator = _line_number;
            if (_line_square < 0)
                _line_square = _line_separator;

            if (_line_background < 0)
                _line_background = _background;

            _colors[_foreground= __default_name;

            
#endregion

            return true;
        
}
        private IEnumerable<string> MakeCssCore()
        {
            #region head
            var head = @"
@charset """ + __encoding.WebName.ToLower() + @""";

span
{
    margin: 0px!important;
    padding: 0px!important;
    display: inline;
}
div." + this.ClassName + @"
{
    margin: 0px;
    padding: 0px;
    width: auto;
    max-height: 700px;
    overflow: scroll;

    background-color: " + this.ColorCodeBackground + @";
}
div." + this.ClassNameCode + @"
{
    margin: 0px!important;
    padding: 0px!important;
    float: auto!important;
    width: auto!important;
    font-family: ""MS Gothic"", monospace!important;
    font-size: 14px!important;
    text-align: left!important;
    line-height: 14px!important;
    white-space: pre!important;

    color: " + this.ColorCodeForeground + @";
    background-color: " + this.ColorCodeBackground + @";
}
div." + this.ClassNameLineNumber + @"
{
    margin: 0px!important;
    padding: 0px!important;
    float: left!important;
    width: auto!important;
    font-family: ""MS Gothic"", monospace!important;
    font-size: 14px!important;
    text-align: left!important;
    line-height: 14px!important;
    white-space: pre!important;

    color: " + this.ColorCodeLineNumber + @";
    background-color: " + this.ColorCodeLineBackground + @";
}
";
            
#endregion

            var class_names = __link_names.Split('|').ToHashSet();
            var special_colors = TypeInference.Array
            (
                TypeInference.Array(__linenum_namethis.ColorCodeLineNumberthis.ColorCodeLineBackground),
                TypeInference.Array(__linespr_namethis.ColorCodeLineSeparatorthis.ColorCodeLineBackground),
                TypeInference.Array(__linesqr_namethis.ColorCodeLineSquarethis.ColorCodeLineBackground),
                TypeInference.Array(__linesqr_end_namethis.ColorCodeLineSquarethis.ColorCodeLineBackground),
                TypeInference.Array(__collapsed_namethis.ColorCodeCollapsedForegroundthis.ColorCodeCollapsedBackground)
            );
            var colors_css = _colors
                .Select(pair => "code." + pair.Value + " { color: " + ColorCode(pair.Key+ "; }")
                .ConcatItem("code." + __space_name + " { color: " + this.ColorCodeBackground + "; }")
                .Concat(special_colors.Select(
                    array => "code." + array[0+ " { color: " + array[1+ "; background-color: " + array[2+ "; }"
                ))
                .Concat(_colors
                    .Where(pair => class_names.Contains(pair.Value))
                    .Select(pair => "a." + pair.Value + " { color: " + ColorCode(pair.Key+ "; }")
                )
                .ConcatInFirst(head);

            return colors_css;
        
}

        
#endregion
    
}
}