// Created with MonoDevelop
//
//    QuickStep: Acquire, view and identify spectra 
//    Copyright (C) 2021 Torsten Schache, 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.Collections.Generic;
using System.Linq;
using System.Reflection;
using Gdk;
using Hiperscan.ApoIdentCore.Enums;
using Hiperscan.GtkExtensions.Widgets;
using Hiperscan.Unix;

namespace Hiperscan.Extensions.ApoIdent.Widgets
{
    public class MeasuringButton
    {
        public const int DEFAULT_SIZE = 60;
        public const int DEFAULT_ALIGNMENT = 18;

        public MeasuringButton(Gtk.Button measuring_button, Gtk.Button abort_button, Gtk.Label label)
        {
            this.ExecuteButton = measuring_button;
            this.AbortButton = abort_button;
            this.ExecuteButton.Image = this.GtkImage;
            this.GtkLabel = label;

            this.InitIcons();
            this.InitAdvices();
            this.CurrentState = ProgramState.None;
            this.Sensitive = false;
        }

        protected void InitIcons()
        {
            string resource_tmplate = "Hiperscan.Extensions.ApoIdent.Widgets.MeasringButton.Icons.{0}.png";

            HashSet<string> all_resources = Assembly.GetExecutingAssembly().GetManifestResourceNames().ToHashSet();

            foreach (ProgramState state in Enum.GetValues(typeof(ProgramState)))
            {
                string resource = String.Format(resource_tmplate, state.ToString());
                if (all_resources.Contains(resource) == false)
                    continue;

                Pixbuf buf = new Gdk.Pixbuf(null, resource, 
                                            this.ButtonSize, 
                                            this.ButtonSize);
   
                this.StateIcons.Add(state, buf);
            }
        }

        private void InitAdvices()
        {
            string message = String.Empty;
            this.StateAdvices.Add(ProgramState.None, message);

            message = Catalog.GetString("Please apply the black reference.");
            this.StateAdvices.Add(ProgramState.MeasuringBlackReference, message);

            message = Catalog.GetString("Please apply the sample insert white reference.");
            this.StateAdvices.Add(ProgramState.MeasuringWhiteInsertReference, message);

            message = Catalog.GetString("Please apply the white reference.");
            this.StateAdvices.Add(ProgramState.MeasuringWhiteReference, message);

            message = Catalog.GetString("The substance cannot be measured by Apo-Ident.");
            this.StateAdvices.Add(ProgramState.NotMeasurable, message);

            message = Catalog.GetString(@"Place the transflectance insert feet facing
down in an empty sample container and use them
for the next measurement too");

            this.StateAdvices.Add(ProgramState.MeasuringTransflectance, message);
            this.StateAdvices.Add(ProgramState.MeasuringTransflectanceAu, message);

            message = Catalog.GetString(@"Please use the same transflectance insert and
sample container for the transflectance reference
measurement and your substance measurement.");
            this.StateAdvices.Add(ProgramState.MeasuringFluid, message);

            message = Catalog.GetString(@"Place the sample insert container with your
selected substance on the device.");
            this.StateAdvices.Add(ProgramState.MeasuringInsert, message);

            message = Catalog.GetString("Place the selected substance on the device.");
            this.StateAdvices.Add(ProgramState.MeasuringSolid, message);
            this.StateAdvices.Add(ProgramState.MeasuringCannabis, message);
        }

        public bool Sensitive
        {
            set
            {
                this.ExecuteButton.Sensitive = value;
                this.AbortButton.Sensitive = value;
                this.GtkLabel.Sensitive = value;
            }
        }


        private ProgramState current_state = ProgramState.None;
        public ProgramState CurrentState
        {
            private get
            {
                return this.current_state;
            }

            set
            {
                this.AbortButton.Visible = false;

                switch (value)
                {
                    case ProgramState.MeasuringWhiteReference:
                    case ProgramState.MeasuringWhiteInsertReference:
                    case ProgramState.MeasuringBlackReference:
                        this.AbortButton.Visible = true;
                        break;

                    default:
                        break;
                }

                this.current_state = value;
                this.GtkImage.Pixbuf = this.StateIcons[value];
                this.GtkLabel.Text = this.StateAdvices[value];
            }
        }

        private int measuring_button_size = MeasuringButton.DEFAULT_SIZE;
        public int ButtonSize
        {
            get
            {
                return this.measuring_button_size;
            }
            set
            {
                this.measuring_button_size = value;
                this.InitIcons();
                this.GtkImage.Pixbuf = this.StateIcons[this.CurrentState];
            }
        }

        private double button_alignment = MeasuringButton.DEFAULT_ALIGNMENT;
        public double ButtonAlignment
        {
            get
            {
                return this.button_alignment;
            }
            set
            {
                this.button_alignment = value;
                ((Gtk.Alignment)this.ExecuteButton.Parent).Xalign = (float)value / 100;
            }
        }

        private Dictionary<ProgramState, string> StateAdvices { get; set; } = new Dictionary<ProgramState, string>();
        private Dictionary<ProgramState, Pixbuf> StateIcons { get; set; } = new Dictionary<ProgramState, Pixbuf>();

        private Gtk.Button ExecuteButton { get; set; }
        private Gtk.Button AbortButton { get; set; }
        private Gtk.Label GtkLabel { get; set; }
        private Gtk.Image GtkImage { get; set; } = new Gtk.Image();
    }
}
