using System;
using System.Collections.Generic;
using System.Drawing;

namespace FooEditEngine.Windows
{
    class PrintableTextLayout : ITextLayout
    {
        public PrintableTextLayout(Font font)
        {
            this.Disposed = false;
            this.Height = font.Height;
        }
        public double Width
        {
            get { return 0; }
        }

        public double Height
        {
            get;
            private set;
        }

        public bool Disposed
        {
            get;
            private set;
        }

        public bool Invaild
        {
            get { return false; }
        }

        public int GetIndexFromX(double x)
        {
            return 0;
        }

        public double GetWidthFromIndex(int index)
        {
            return 0;
        }

        public double GetXFromIndex(int index)
        {
            return 0;
        }

        public int AlignIndexToNearestCluster(int index, AlignDirection flow)
        {
            return 0;
        }

        public void Dispose()
        {
            this.Disposed = true;
        }
    }
    class PrintableTextRender : IPrintableTextRender
    {
        StringFormat sf;
        Font font;
        Graphics g;

        public PrintableTextRender(Font font, Graphics g)
        {
            this.font = font;
            this.sf = StringFormat.GenericTypographic;
            this.sf.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
            this.g = g;
        }

        public event ChangedRenderResourceEventHandler ChangedRenderResource;
        public event EventHandler ChangedRightToLeft;

        public void BeginDraw(Graphics g)
        {
            this.g = g;
            if(this.RightToLeft)
                this.sf.FormatFlags |= StringFormatFlags.DirectionRightToLeft;
        }

        public void EndDraw()
        {
        }

        public ITextLayout CreateLaytout(string str)
        {
            return new PrintableTextLayout(this.font);
        }

        public float HeaderHeight { get { return this.font.Height; } }

        public float FooterHeight { get { return this.font.Height; } }

        const int LineNumberFiledLength = 6;

        public double LineNemberWidth
        {
            get
            {
                int length = LineNumberFiledLength;
                length++;   //余白を確保する
                SizeF metrics = g.MeasureString("0", this.font, Int16.MaxValue, this.sf);
                return metrics.Width * length;
            }
        }

        public double FoldingWidth
        {
            get
            {
                return 0;
            }
        }

        public bool RightToLeft
        {
            get;
            set;
        }

        public bool InsertMode
        {
            get;
            set;
        }

        public Rectangle TextArea
        {
            get;
            set;
        }

        public Size emSize
        {
            get
            {
                return new Size(0, 0);
            }
        }

        public void DrawCachedBitmap(Rectangle rect)
        {
        }

        public void CacheContent()
        {
        }

        public bool IsVaildCache()
        {
            return false;
        }

        public void DrawLine(Point from, Point to)
        {
        }

        public void DrawString(string str, double x, double y)
        {
            g.DrawString(str, this.font, new SolidBrush(this.Foreground), new PointF((float)x, (float)y), this.sf);
        }

        public void DrawCaret(Rectangle rect, bool transparent)
        {
        }

        public void DrawFoldingMark(bool expand, double x, double y)
        {
        }

        public void DrawString(string str, double x, double y, StringAlignment align, Size layoutRect)
        {
            System.Drawing.StringAlignment old = this.sf.Alignment;
            
            this.sf.Alignment = System.Drawing.StringAlignment.Center;

            g.DrawString(str, this.font, new SolidBrush(this.Foreground), new RectangleF((float)x, (float)y, (float)layoutRect.Width, (float)layoutRect.Height), this.sf);
            
            this.sf.Alignment = old;
        }

        public void DrawOneLine(LineToIndexTable lti, int row, double x, double y, IEnumerable<Selection> SelectRanges)
        {           
            g.DrawString(lti[row], this.font, new SolidBrush(this.Foreground), new RectangleF((float)x, (float)y, (float)this.TextArea.Width, (float)this.TextArea.Height), this.sf);
        }

        public void FillRectangle(Rectangle rect, FillRectType type)
        {
        }

        public void FillBackground(Rectangle rect)
        {
        }

        public ITextLayout CreateLaytout(string str, SyntaxInfo[] syntaxCollection, IEnumerable<Marker> MarkerRanges)
        {
            return new PrintableTextLayout(this.font);
        }

        public List<LineToIndexTableData> BreakLine(Document doc,int startIndex,int endIndex,double maxwidth)
        {
            List<LineToIndexTableData> output = new List<LineToIndexTableData>();

            foreach (string str in doc.GetLines(startIndex, endIndex))
            {
                LineToIndexTableData info = new LineToIndexTableData();

                if (str.Length == 0)
                {
                    info.Index = startIndex;
                    info.Length = 0;
                    output.Add(info);
                    return output;
                }

                int fitlen, index = 0, x = 0, width;
                do
                {
                    int linesFilled;
                    SizeF metrics = g.MeasureString(str.Substring(index), this.font, new SizeF((float)maxwidth, this.font.Height + 1), this.sf, out fitlen, out linesFilled);

                    x += width = (int)metrics.Width;

                    info.Index = index + startIndex;
                    info.Length = fitlen;
                    output.Add(info);

                    info = new LineToIndexTableData();

                    index += fitlen;
                } while (index < str.Length);

                output[output.Count - 1].LineEnd = true;

                startIndex += str.Length;
            }

            return output;
        }

        public System.Drawing.Color Foreground
        {
            get;
            set;
        }

        public int TabWidthChar
        {
            get { float taboffset; return (int)this.sf.GetTabStops(out taboffset)[0]; }
            set { this.sf.SetTabStops(0,new float[]{value});}
        }

    }
}
