namespace BayesServer.HelpSamples
{
    using Inference;
    using Inference.RelevanceTree;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    public static class DecisionGraphExample
    {
        public static void Main()
        {
            
            
            
            
            
            var network = new Network();
            
            var oilDry = new State("Dry");
            var oilWet = new State("Wet");
            var oilSoaking = new State("Soaking");
            var oil = new Variable("Oil", oilDry, oilWet, oilSoaking);
            var nodeOil = new Node(oil);
            network.Nodes.Add(nodeOil);
            var testResultClosed = new State("Closed");
            var testResultOpen = new State("Open");
            var testResultDiffuse = new State("Diffuse");
            var testResult = new Variable("Test Result", testResultClosed, testResultOpen, testResultDiffuse);
            var nodeTestResult = new Node(testResult);
            network.Nodes.Add(nodeTestResult);
            
            var testYes = new State("Yes");
            var testNo = new State("No");
            var test = new Variable("Test?", VariableValueType.Discrete, VariableKind.Decision);
            test.States.Add(testYes);
            test.States.Add(testNo);
            var nodeTest = new Node(test);
            network.Nodes.Add(nodeTest);
            var drillYes = new State("Yes");
            var drillNo = new State("No");
            var drill = new Variable("Drill?", VariableValueType.Discrete, VariableKind.Decision);
            drill.States.Add(drillYes);
            drill.States.Add(drillNo);
            var nodeDrill = new Node(drill);
            network.Nodes.Add(nodeDrill);
            
            
            var drillUtility = new Variable("Drill utility", VariableValueType.Continuous, VariableKind.Utility);
            var nodeDrillUtility = new Node(drillUtility);
            network.Nodes.Add(nodeDrillUtility);
            var testUtility = new Variable("Test utility", VariableValueType.Continuous, VariableKind.Utility);
            var nodeTestUtility = new Node(testUtility);
            network.Nodes.Add(nodeTestUtility);
            
            
            
            
            
            var meu = new Variable("MEU", VariableValueType.Continuous, VariableKind.Utility);
            var nodeMeu = new Node(meu);
            network.Nodes.Add(nodeMeu);
            
            var links = network.Links;
            links.Add(new Link(nodeOil, nodeTestResult));
            links.Add(new Link(nodeOil, nodeDrillUtility));
            links.Add(new Link(nodeTestResult, nodeDrill));
            links.Add(new Link(nodeTest, nodeTestResult));
            links.Add(new Link(nodeTest, nodeDrill));
            links.Add(new Link(nodeTest, nodeTestUtility));
            links.Add(new Link(nodeDrill, nodeDrillUtility));
            links.Add(new Link(nodeDrillUtility, nodeMeu));
            links.Add(new Link(nodeTestUtility, nodeMeu));
            
            
            var tableOil = nodeOil.NewDistribution().Table;
            tableOil[oilDry] = 0.5;
            tableOil[oilWet] = 0.3;
            tableOil[oilSoaking] = 0.2;
            nodeOil.Distribution = tableOil;
            var tableTestResult = nodeTestResult.NewDistribution().Table;
            
            
            
            var third = 1.0 / 3.0;
            new TableIterator(
                tableTestResult,
                new Node[] { nodeOil, nodeTest, nodeTestResult }
                ).CopyFrom(
                new double[]{
                    0.1, 0.3, 0.6, third, third, third, 0.3, 0.4, 0.3, third, third, third, 0.5, 0.4, 0.1, third, third, third});
            nodeTestResult.Distribution = tableTestResult;
            var tableTest = nodeTest.NewDistribution().Table;
            tableTest.Normalize(true);  
            nodeTest.Distribution = tableTest;
            var tableDrill = nodeDrill.NewDistribution().Table;
            tableDrill.Normalize(true); 
            nodeDrill.Distribution = tableDrill;
            
            
            
            
            var gaussianDrillUtility = (CLGaussian)nodeDrillUtility.NewDistribution();
            gaussianDrillUtility.SetMean(drillUtility, -70.0, oilDry, drillYes);
            gaussianDrillUtility.SetMean(drillUtility, 0.0, oilDry, drillNo);
            gaussianDrillUtility.SetMean(drillUtility, 50.0, oilWet, drillYes);
            gaussianDrillUtility.SetMean(drillUtility, 0.0, oilWet, drillNo);
            gaussianDrillUtility.SetMean(drillUtility, 200.0, oilSoaking, drillYes);
            gaussianDrillUtility.SetMean(drillUtility, 0.0, oilSoaking, drillNo);
            nodeDrillUtility.Distribution = gaussianDrillUtility;
            var gaussianTestUtility = (CLGaussian)nodeTestUtility.NewDistribution();
            gaussianTestUtility.SetMean(testUtility, -10.0, testYes);
            gaussianTestUtility.SetMean(testUtility, 0.0, testNo);
            nodeTestUtility.Distribution = gaussianTestUtility;
            
            
            var gaussianMeu = (CLGaussian)nodeMeu.NewDistribution();
            gaussianMeu.SetWeight(meu, drillUtility, 1.0);
            gaussianMeu.SetWeight(meu, testUtility, 1.0);
            nodeMeu.Distribution = gaussianMeu;
            
            
            var factory = new RelevanceTreeInferenceFactory();
            var inference = factory.CreateInferenceEngine(network);
            var queryOptions = factory.CreateQueryOptions();
            var queryOutput = factory.CreateQueryOutput();
            
            
            queryOptions.DecisionAlgorithm = DecisionAlgorithm.SinglePolicyUpdatingLight;
            var queryOil = new Table(oil);    
            var queryDrill = new Table(drill);  
            var queryMeu = new CLGaussian(meu); 
            var queryJoint = new CLGaussian(new Variable[] { meu, oil });   
            var queryDistributions = inference.QueryDistributions;
            queryDistributions.Add(queryOil);
            queryDistributions.Add(queryDrill);
            queryDistributions.Add(queryMeu);
            queryDistributions.Add(queryJoint);
            
            
            
            inference.Query(queryOptions, queryOutput);
            var oilDryValue = queryOil[oilDry];
            Console.WriteLine("Oil = Dry\t{0}", oilDryValue);   
            var meuValue = queryMeu.GetMean(meu);
            Console.WriteLine("MEU\t{0}", meuValue);   
            var drillYesValue = queryDrill[drillYes];
            Console.WriteLine("Drill? = Yes\t{0}", drillYesValue);   
            var meuOilDry = queryJoint.GetMean(meu, oilDry);    
            Console.WriteLine("MEU Oil=Dry\t{0}", meuOilDry);   
        }
    }
}