namespace BayesServer.HelpSamples
{
    using System;
    using BayesServer.Data.Sampling;
    using BayesServer.Inference;
    public static class DataSampling
    {
        public static void Main()
        {
            
            var network = CreateNetwork();
            var gender = network.Variables["Gender"];
            var height = network.Variables["Height"];
            var hairLength = network.Variables["Hair Length"];
            
            
            var fixedEvidence = new Evidence(network);
            fixedEvidence.SetState(gender.States["Female", true]);
            
            var sampler = new DataSampler(network, fixedEvidence);
            var options = new DataSamplingOptions();
            
            
            var random = new RandomDefault(0);
            var evidence = new Evidence(network);
            
            Console.WriteLine("Gender\tHeight\tHair Length");
            Console.WriteLine("------------------------------");
            for (int i = 0; i < 100; i++)
            {
                try
                {
                    sampler.TakeSample(evidence, random, options);
                    Console.WriteLine("{0}\t{1}\t{2}",
                        ValueAsText(gender, evidence),
                        ValueAsText(height, evidence),
                        ValueAsText(hairLength, evidence));
                }
                catch (InconsistentEvidenceException)
                {
                    Console.WriteLine("Inconsistent evidence exception was raised.");
                }
            }
        }
        private static string ValueAsText(Variable variable, IEvidence evidence)
        {
            if(evidence.GetEvidenceType(variable) == EvidenceType.None)
                return "(null)";
            if (variable.ValueType == VariableValueType.Continuous)
            {
                return evidence.Get(variable).Value.ToString("N2");
            }
            else
            {
                return variable.States[evidence.GetState(variable).Value].Name;
            }
        }
        private static Network CreateNetwork()
        {
            var network = new Network();
            var nodeGender = new Node("Gender", new string[] { "Female", "Male" });
            network.Nodes.Add(nodeGender);
            var nodeHeight = new Node("Height", VariableValueType.Continuous);
            network.Nodes.Add(nodeHeight);
            var nodeHairLength = new Node("Hair Length", new string[] { "Short", "Medium", "Long" });
            network.Nodes.Add(nodeHairLength);
            network.Links.Add(new Link(nodeGender, nodeHeight));
            network.Links.Add(new Link(nodeGender, nodeHairLength));
            
            
            var tableGender = nodeGender.NewDistribution().Table;
            tableGender.CopyFrom(new double[] { 0.51, 0.49 });
            nodeGender.Distribution = tableGender;
            var tableHairLength = nodeHairLength.NewDistribution().Table;
            var iteratorHairLength = new TableIterator(tableHairLength, new Node[] { nodeGender, nodeHairLength });
            iteratorHairLength.CopyFrom(new double[] { 0.1, 0.4, 0.5, 0.8, 0.15, 0.05 });
            nodeHairLength.Distribution = tableHairLength;
            var gaussianHeight = (CLGaussian)nodeHeight.NewDistribution();
            
            gaussianHeight.SetMean(0, 0, 162.56);
            gaussianHeight.SetVariance(0, 0, 50.58);
            
            gaussianHeight.SetMean(1, 0, 176.022);
            gaussianHeight.SetVariance(1, 0, 50.58);
            nodeHeight.Distribution = gaussianHeight;
            
            network.Validate(new ValidationOptions());
            return network;
        }
    }
}