using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.IO;
using System.Text;
using System.Windows.Forms;
using StarEngine;
using Ruby;
using VALUE = System.Int32;

namespace StarEngine.Ruby
{
    public partial class RubyInterpreter
    {
        private void InitializeFontClass()
        {
            VALUE cFont = SERubyConsts.ForName("Font");

            RUBY.rb_define_private_method(cFont, "__cs_initialize__", this.mFont_cs_initialize);
            RUBY.rb_define_method(cFont, "get_size", this.mFont_get_size);
            RUBY.rb_define_singleton_method(cFont, "exist?", this.mFont_exist);
        }

        private VALUE mFont_cs_initialize(VALUE self, VALUE rbName, VALUE rbSize, VALUE rbStyles)
        {
            RUBY.Send(self, "__cs_set_finalizer__");

            float csSize = (float)RUBY.NUM2DBL(rbSize);
            FontStyle csStyles = FontStyle.Regular;
            if (RUBY.ToBool(RUBY.HashAref(rbStyles, "bold")))
                csStyles |= FontStyle.Bold;
            if (RUBY.ToBool(RUBY.HashAref(rbStyles, "italic")))
                csStyles |= FontStyle.Italic;

            FontFamily csFontFamily;
            string csName = RUBY.StringValuePtr(rbName);
            string csFullPath = PathExtensions.GetFullPathAndExtension(csName);
            if (!FontExists(csName))
            {
                RUBY.rb_raise(SERubyConsts.ForName("::Errno::ENOENT"), csName);
                return RUBY.Qnil;
            }
            try
            {
                if (File.Exists(csFullPath))
                {
                    PrivateFontCollection pfc = new PrivateFontCollection();
                    pfc.AddFontFile(csFullPath);
                    csFontFamily = pfc.Families[0];
                }
                else
                {
                    csFontFamily = new FontFamily(csName);
                }
            }
            catch (FileNotFoundException)
            {
                RUBY.rb_raise(SERubyConsts.ForName("StarEngineError"), "invalid font file");
                return RUBY.Qnil;
            }

            Font csFont = new Font(csFontFamily, csSize, csStyles, GraphicsUnit.Pixel);

            RUBY.rb_iv_set(self, "@size", RUBY.rb_float_new(csFont.Size));
            RUBY.rb_iv_set(self, "@name", RUBY.rb_str_new2(csFont.Name));
            RUBY.rb_iv_set(self, "@bold", csFont.Bold ? RUBY.Qtrue : RUBY.Qfalse);
            RUBY.rb_iv_set(self, "@italic", csFont.Italic ? RUBY.Qtrue : RUBY.Qfalse);

            this.AddCachedObject(self, csFont);
            return RUBY.Qnil;
        }

        private VALUE mFont_get_size(VALUE self, VALUE rbText)
        {
            Font csFont = this.GetCachedObject<Font>(self);
            string csText = RUBY.StringValuePtr(rbText);
            csText = csText.Replace('\r', ' ').Replace('\n', ' ').Replace('\t', ' ').Replace(' ', '\u00a0');

            VALUE rbArray = RUBY.rb_ary_new();

            using (Bitmap b = new Bitmap(1, 1))
            using (Graphics g = Graphics.FromImage(b))
            {
                StringFormat sf = StringFormat.GenericTypographic;
                SizeF csSizeF = g.MeasureString(csText, csFont, int.MaxValue, sf);
                Size csSize = Size.Ceiling(csSizeF);
                RUBY.rb_ary_push(rbArray, RUBY.INT2NUM(csSize.Width));
                RUBY.rb_ary_push(rbArray, RUBY.INT2NUM(csSize.Height));
            }
            return rbArray;
        }

        private VALUE mFont_exist(VALUE self, VALUE rbName)
        {
            string csName = RUBY.StringValuePtr(rbName);
            return FontExists(csName) ? RUBY.Qtrue : RUBY.Qfalse;
        }

        private static bool FontExists(string nameOrPath)
        {
            InstalledFontCollection ifc = new InstalledFontCollection();
            if (Array.Exists(ifc.Families, delegate(FontFamily ff)
            {
                return ff.Name == nameOrPath;
            }))
                return true;

            string fullPath = PathExtensions.GetFullPathAndExtension(nameOrPath);
            return File.Exists(fullPath);
        }
    }
}
