namespace BayesServer.HelpSamples
{
    using System;
    using System.Collections.Generic;
    using System.Text;
    using BayesServer.Data;
    using System.Data;
    using BayesServer.Inference.RelevanceTree;
    public static class BatchQueryExample
    {
        public static void Main()
        {
            var network = new Network();
            
            
            network.Load(@"Waste.bayes");
            
            var burningRegimen = network.Variables["Burning Regimen"];
            var wasteType = network.Variables["Waste type", true];
            var filterState = network.Variables["Filter state", true];
            var burningRegimenStable = burningRegimen.States["Stable", true];
            
            var filterEfficiency = network.Variables["Filter efficiency", true];
            var dustEmission = network.Variables["Dust emission", true];
            var metalsInWaste = network.Variables["Metals in waste", true];
            var co2Concentration = network.Variables["CO2 concentration", true];
            var lightPenetrability = network.Variables["Light penetrability", true];
            var metalsEmission = network.Variables["Metals emission", true];
            
            
            
            
            var factory = new RelevanceTreeInferenceFactory();
            var inference = factory.CreateInferenceEngine(network);
            var queryOptions = factory.CreateQueryOptions();
            var queryOutput = factory.CreateQueryOutput();
            
            var queryBurningRegimen = new Table(burningRegimen);
            inference.QueryDistributions.Add(queryBurningRegimen);
            var queryLightPenetrability = new CLGaussian(lightPenetrability);
            inference.QueryDistributions.Add(queryLightPenetrability);
            
            var queryJoint = new CLGaussian(new Variable[] { filterEfficiency, burningRegimen });
            inference.QueryDistributions.Add(queryJoint);
            
            queryOptions.LogLikelihood = true;
            var evidenceReaderCommand = CreateEvidenceReaderCommand(network);
            var readOptions = new ReadOptions();
            
            
            
            using (var evidenceReader = evidenceReaderCommand.ExecuteReader())
            {
                while (evidenceReader.Read(inference.Evidence, readOptions))
                {
                    inference.Query(queryOptions, queryOutput);
                    var logLikelihood = queryOutput.LogLikelihood.Value;
                    var probStable = queryBurningRegimen[burningRegimenStable];
                    var meanLightPenetrability = queryLightPenetrability.GetMean(lightPenetrability);
                    var varianceLightPenetrability = queryLightPenetrability.GetVariance(lightPenetrability);
                    var jointElement = queryJoint.GetMean(filterEfficiency, burningRegimenStable);
                    Console.WriteLine($"{logLikelihood}\t{probStable}\t{meanLightPenetrability}\t{varianceLightPenetrability}\t{jointElement}");
                }
            }
        }
        
        
        
        
        
        private static IEvidenceReaderCommand CreateEvidenceReaderCommand(Network network)
        {
            var dataReaderCommand = CreateDataReaderCommand();
            var wasteType = network.Variables["Waste type", true];
            var co2Concentration = network.Variables["CO2 concentration", true];
            return new EvidenceReaderCommand(
                dataReaderCommand,
                new VariableReference[]
                {
                    new VariableReference(wasteType, ColumnValueType.Name, wasteType.Name),
                    new VariableReference(co2Concentration, ColumnValueType.Value, co2Concentration.Name),
                },
                new ReaderOptions()
                );
        }
        
        
        
        
        
        private static IDataReaderCommand CreateDataReaderCommand()
        {
            var table = new DataTable();
            var wasteType = table.Columns.Add("Waste type", typeof(string));
            var co2Concentration = table.Columns.Add("CO2 concentration", typeof(double));
            
            table.Rows.Add("Industrial", -1.7);
            table.Rows.Add("Household", -2.0);
            table.Rows.Add(null, -1.7);
            table.Rows.Add("Industrial", null);
            table.Rows.Add("Industrial", 0.5);
            return new DataTableDataReaderCommand(table);
        }
        
        
        
        
        
        
    }
}