// Created with MonoDevelop
//
//    QuickStep: Acquire, view and identify spectra 
//    Copyright (C) 2023, Hiperscan GmbH Dresden, Germany
//
//    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.Threading;
using System.Threading.Tasks;

namespace Hiperscan.Extensions.ApoIdent
{
    public class FlexEllipsizeLabel
    {
        public FlexEllipsizeLabel(Gtk.Label label)
        {
            this.Label = label;
            this.Alignment = (Gtk.Alignment)this.Label.Parent;
            this.Table = (Gtk.Table)this.Alignment.Parent;
            this.TableChild = (Gtk.Table.TableChild)this.Table[this.Alignment];
            this.SetMainWindow(this.Label);

            this.Label.SizeAllocated += this.OnLabelSizeAllocated;
            this.CurrentTableWidth = this.Table.Allocation.Width;
            this.Table.SizeRequested += this.OnTableSizeRequested;
        }

        private void SetMainWindow(Gtk.Widget widget)
        {
            if (widget.Parent == null)
            {
                this.MainWindow = (Gtk.Window)widget;
                this.CurrentWindowWidth = this.MainWindow.Allocation.Width;
                this.MainWindow.SizeAllocated += this.OnWindowSizeAllocated;
                return;
            }

            this.SetMainWindow(widget.Parent);
        }

        private void OnTableSizeRequested(object sender, Gtk.SizeRequestedArgs e)
        {
            if (this.IsMeasuring == true)
                return;

            if (this.SizeIsChanging == false)
                return;

            if (this.IsTableSizeUpdating == true)
            {
                this.IsTableSizeUpdating = false;
                this.SizeIsChanging = false;
                return;
            }

            this.IsTableSizeUpdating = true;
            if (e.Requisition.Width <= this.CurrentTableWidth)
            {
                this.Label.Ellipsize = Pango.EllipsizeMode.None;
                this.TableChild.XOptions = Gtk.AttachOptions.Fill;
            }
            else
            {
                this.Label.Ellipsize = Pango.EllipsizeMode.End;
                this.TableChild.XOptions =Gtk.AttachOptions.Fill | Gtk.AttachOptions.Expand;
            }
        }

        private void OnLabelSizeAllocated(object sender, Gtk.SizeAllocatedArgs e)
        {
            if (this.IsMeasuring)
            {
                this.CurrentTableWidth = this.Table.Allocation.Width;

                this.IsMeasuring = false;
                this.SizeIsChanging = true;
                this.TableChild.XOptions = Gtk.AttachOptions.Fill;
                this.Label.Ellipsize = Pango.EllipsizeMode.None;
            }
        }

        private void OnWindowSizeAllocated(object sender, Gtk.SizeAllocatedArgs e)
        {
            if (this.CurrentWindowWidth != e.Allocation.Size.Width)
            {
                this.CurrentWindowWidth = e.Allocation.Size.Width;

                this.IsMeasuring = true;

                this.Label.Ellipsize = Pango.EllipsizeMode.End;
                this.TableChild.XOptions = Gtk.AttachOptions.Expand | Gtk.AttachOptions.Fill;
            }
        }

        public string Text
        {
            set
            {
                if (this.Label.Text == value)
                    return;

                this.SizeIsChanging = true;
                this.Label.Text = value;
            }
        }

        public bool Sensitive
        {
            set
            {
                this.Label.Sensitive = value;
            }
        }
        
        private int CurrentWindowWidth { get; set; } = 0;
        private int CurrentTableWidth { get; set; } = 0;
        private bool IsMeasuring { get; set; } = false;
        private bool IsTableSizeUpdating { get; set; } = false;
        private bool SizeIsChanging { get; set; }

        private Gtk.Window MainWindow { get; set; }
        private Gtk.Table Table { get; set; }
        private Gtk.Table.TableChild TableChild { get; set; }
        private Gtk.Label Label { get; set; }
        private Gtk.Alignment Alignment { get; set; }
    }
}
