/*
 * Copyright (C) 2013 FooProject
 * * 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;

namespace FooEditEngine
{
    sealed class PrintableView : ViewBase
    {
        public PrintableView(Document doc, IPrintableTextRender r, Padding margin)
            : base (doc,r,margin)
        {
        }

        public string Header
        {
            get;
            set;
        }

        public string Footer
        {
            get;
            set;
        }

        public override void Draw(Rectangle updateRect, bool force = false)
        {
            if (this.LayoutLines.Count == 0)
                return;

            if (this.Hilighter != null)
                this.Hilighter.Reset();

            Point pos = this.render.TextArea.TopLeft;
            pos.X -= Src.X;

            int endRow = Math.Min(this.LayoutLines.Count - 1, Src.Row + this.LineCountOnScreen - 1);

            Size lineNumberSize = new Size(this.render.LineNemberWidth, this.render.TextArea.Height);

            IPrintableTextRender render = (IPrintableTextRender)this.render;

            //ヘッダーを印刷する
            if (this.Header != null && this.Header != string.Empty)
            {
                this.render.DrawString(this.Header, pos.X, pos.Y, StringAlignment.Center,
                    new Size(render.TextArea.Width - this.GetRealtiveX(AreaType.TextArea),render.FooterHeight));

                pos.Y += (int)render.HeaderHeight;
            }

            //レイアウト行を印刷する
            for (int i = Src.Row; i <= endRow; i++)
            {
                double lineHeight = this.LayoutLines.GetLayout(i).Height;

                this.render.DrawOneLine(this.Document, this.LayoutLines,i, pos.X + this.render.TextArea.X, pos.Y);

                if (this.Document.DrawLineNumber)
                    this.render.DrawString((i + 1).ToString(), this.PageBound.X + this.GetRealtiveX(AreaType.LineNumberArea), pos.Y, StringAlignment.Right, lineNumberSize);

                pos.Y += lineHeight;
            }

            //フッターを印刷する
            if (this.Footer != null && this.Footer != string.Empty)
            {
                pos.Y = render.TextArea.Bottom;
                this.render.DrawString(this.Footer, pos.X, pos.Y, StringAlignment.Center,
                    new Size(render.TextArea.Width - this.GetRealtiveX(AreaType.TextArea), render.FooterHeight));
            }

            return;
        }

        public bool TryPageDown()
        {
            return base.TryScroll(this.Src.X, this.Src.Row + this.LineCountOnScreen);
        }

        protected override void CalculateClipRect()
        {
            double x, y, width, height;

            if (this.Document.DrawLineNumber)
            {
                if (this.render.RightToLeft)
                    x = this.Padding.Left;
                else
                    x = this.render.LineNemberWidth + this.render.emSize.Width + this.Padding.Left + this.LineNumberMargin;
                width = this.PageBound.Width - this.render.LineNemberWidth - this.render.emSize.Width - this.Padding.Right - this.Padding.Left - this.LineNumberMargin;
            }
            else
            {
                x = this.Padding.Left;
                width = this.PageBound.Width  - this.Padding.Right - this.Padding.Left;
            }

            y = this.Padding.Top;
            height = this.PageBound.Height - this.Padding.Bottom - this.Padding.Top;

            if (width < 0)
                width = 0;

            if (height < 0)
                height = 0;

            IPrintableTextRender render = (IPrintableTextRender)this.render;

            if (this.Footer != null && this.Footer != string.Empty)
                height -= render.FooterHeight;
            if (this.Header != null && this.Header != string.Empty)
                height -= render.HeaderHeight;

            this.render.TextArea = new Rectangle(x, y, width, height);
        }

        public override void CalculateLineCountOnScreen()
        {
            if (this.LayoutLines.Count == 0)
                return;

            double y = 0;
            int i = this.Src.Row;
            for (; true; i++)
            {
                int row = i < this.LayoutLines.Count ? i : this.LayoutLines.Count - 1;

                ITextLayout layout = this.LayoutLines.GetLayout(row);

                double lineHeight = layout.Height;

                y += lineHeight;

                if (y >= this.render.TextArea.Height)
                    break;
            }
            this.LineCountOnScreen = Math.Max(i - this.Src.Row - 1, 0); //ループを抜けると+1されている
        }

        enum AreaType
        {
            LineNumberArea,
            TextArea
        }

        double GetRealtiveX(AreaType type)
        {
            switch (type)
            {
                case AreaType.LineNumberArea:
                    if (this.Document.DrawLineNumber == false)
                        throw new InvalidOperationException();
                    if (this.render.RightToLeft)
                        return this.PageBound.TopRight.X - this.render.LineNemberWidth;
                    else
                        return this.render.TextArea.X - this.render.LineNemberWidth - this.render.emSize.Width - this.LineNumberMargin;
                case AreaType.TextArea:
                    return this.render.TextArea.X;
            }
            throw new ArgumentOutOfRangeException();
        }
    }
}
