using BoFilTest.Domain;
using BoFilTest.Utils;
using Optional.Collections;
using System;
using System.Linq;

namespace BoFilTest.Export
{
    abstract class BasicExcelExport : IExcelExport
    {
        public  readonly DataModel dataModel;
        public readonly ConfiguredExporter exporter;

        public BasicExcelExport(DataModel dataModel, ConfiguredExporter exporter)
        {
            this.dataModel = dataModel;
            this.exporter = exporter;
        }

        public abstract string Run();
        
        public string CalibrationCurveTextFor(int index)
        {
            switch (index)
            {
                case 0: return Translated.FromKey("CALIBRATION_CURVE_SETTING_1");
                case 1: return Translated.FromKey("CALIBRATION_CURVE_SETTING_2");
                default: throw new ArgumentException();
            }
        }

        public void WriteCommon()
        {
            var form = dataModel.Form;
            var endForm = dataModel.AfterTestForm;

            // Things from the input form
            exporter.Set("test.number", dataModel.TestNumber);
            exporter.Set("date.time", form.Date);
            exporter.Set("project.number", form.ProjectNumber);
            exporter.Set("purchase.order.number", form.PurchaseOrderNumber);
            exporter.Set("client", form.Client);
            exporter.Set("test.operator", form.TestOperator);
            exporter.Set("lab.equipment", form.LabEquipment);
            exporter.Set("valid.for.analysis", endForm.ValidForAnalysis);
            exporter.Set("remarks", endForm.Notes);
            exporter.Set("product", form.Product);
            exporter.Set("product.number", form.ProductNumber);

            exporter.Set("solid.density", form.SolidDensity);
            exporter.Set("liquid.density", form.LiquidDensity);
            exporter.Set("dyn.viscosity", form.DynamicViscosity);
            exporter.Set("suspension.concentration", form.SuspensionConcentration);
            exporter.Set("suspension.temperature", form.SuspensionTemperature);
            exporter.Set("flocculant.type", form.FlocculantType);
            exporter.Set("flocculant.concentration", form.FlocculantConcentration);
            exporter.Set("flocculant.amount", form.FlocculantAmount);
            exporter.Set("washing.medium", form.WashingMedium);
            exporter.Set("washing.fluid.temperature", form.WashingFluidTemperature);
            exporter.Set("washing.amount.1", form.WashingPassFluidAmount.ElementAtOrNone(0));
            exporter.Set("washing.amount.2", form.WashingPassFluidAmount.ElementAtOrNone(1));
            exporter.Set("washing.amount.3", form.WashingPassFluidAmount.ElementAtOrNone(2));
            exporter.Set("gas.temperature", form.GasTemperature);
            exporter.Set("filter.cloth", form.FilterCloth);
            exporter.Set("filter.area", form.FilterArea);
            exporter.Set("filtration.pressure.difference", form.FilterPressureDifference);
            exporter.Set("demoisturization.ratio", form.DemoisturizationRatio);
            exporter.Set("press.pressure", form.PressPressure);

            exporter.Set("cake.consistency", endForm.CakeConsistency);
            exporter.Set("cake.cracking", endForm.CakeCracking);
            exporter.Set("edge.dissolution", endForm.EdgeDissolution);
            exporter.Set("cake.height", endForm.CakeHeight);
            exporter.Set("cake.weight.moist.tare", endForm.CakeWeight);
            exporter.Set("tare", endForm.Tare);
            exporter.Set("initial.suspension.weight", endForm.InitialSuspensionWeight);

            exporter.Set("calibration.curve", CalibrationCurveTextFor(dataModel.MeasurementProtocol.CalibrationCurveIndex));

            // Output form (and calculated)
            dataModel.Timings.MatchSome(timings =>
            {
                exporter.Set("cake.formation.time", timings.CakeFormationTime);
                for (int i = 0; i < timings.IntermediateDemoisturizing.Count; ++i)
                {
                    exporter.Set(string.Format("intermediate.demoisturization.time.{0}", i + 1), timings.IntermediateDemoisturizing[i]);
                }
                for (int i = 0; i < timings.CakeWash.Count; ++i)
                {
                    exporter.Set(string.Format("wash.time.{0}", i + 1), timings.CakeWash[i]);
                }
                timings.Press.MatchSome(time => exporter.Set("press.time", time));
                timings.Vaporization.MatchSome(time => exporter.Set("vaporization.time", time));
                timings.GasBreakthrough.MatchSome(time => exporter.Set("gas.breakthrough.time", time));
                exporter.Set("demoisturization.time", timings.Demoisturizing);
            });

            dataModel.GasIntegralForArea.MatchSome(gasIntergral =>
            {
                exporter.Set("gas.integral", gasIntergral);
            });

            var entries = this.dataModel.MeasurementProtocol.All;
            var steps = entries.Select(e => e.Step);
            var times = entries.Select(e => e.RelativeRunningTime);
            var weights = entries.Select(e => e.Values.Weight);
            var flows = entries.Select(e => e.Values.Flow);
            var pressures = entries.Select(e => e.Values.Pressure);
            var extras = entries.Select(e => e.Values.ExtraValue);

            exporter.SetBelow("series.step", steps, (step, cell) => { cell.SetCellValue(step.Denomination); });
            exporter.SetBelow("series.time", times, (time, cell) => { cell.SetCellValue(time.TotalSeconds); });
            exporter.SetBelow("series.weight", weights, (weight, cell) => { cell.SetCellValue(weight.Value); });
            exporter.SetBelow("series.flow", flows, (flow, cell) => { cell.SetCellValue(flow.Value); });
            exporter.SetBelow("series.pressure", pressures, (pressure, cell) => { cell.SetCellValue(pressure.Value); });
            exporter.SetBelow("series.extra", extras, (extra, cell) => { cell.SetCellValue(extra.Value); });
        }
    }
}

