using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    public class Data_struct
    {
        public Dictionary<string, line> lines;
        public List< p_object> inputs;
        public List< p_object> outputs;
        public List< gat> gates;
        int out_done = 0;
        public int max_x;
        public int max_y;
        public void ParseData(net net)
        {
            h = new Hradla();
            lines = new Dictionary<string, line>();
            inputs = new List<p_object>();
            outputs = new List< p_object>();
            gates = new List< gat>();
            foreach (var item in net.inputs)
            {
                io tmp = new io();
                tmp.x = item.x;
                tmp.y = item.y;
                tmp.w = item.w;
                tmp.h = item.h;
                tmp.linename = item.id;
                inputs.Add( tmp);
                if (lines.ContainsKey(item.id))
                {
                }
                else
                {
                    line l = new line();
                    l.outputs = new List<p_object>();
                    lines.Add(item.id, l);
                }
                if (item.x > max_x)
                    max_x = item.x;
                if (item.y > max_y)
                    max_y = item.y;
            }
            foreach (var item in net.outputs)
            {
                io tmp = new io();
                tmp.x = item.x;
                tmp.y = item.y;
                tmp.w = item.w;
                tmp.h = item.h;
                tmp.linename = item.id;
                outputs.Add( tmp);
                if (lines.ContainsKey(item.id))
                {
                    lines[item.id].outputs.Add(tmp);
                    lines[item.id].output = true;
                }
                else
                {
                    line l = new line();
                    l.outputs = new List<p_object>();
                    l.outputs.Add(tmp);
                    l.output = true;
                    lines.Add(item.id, l);
                }
                if (item.x > max_x)
                    max_x = item.x;
                if (item.y > max_y)
                    max_y = item.y;
            }
            foreach (var item in net.gates)
            {
                gat g = new gat();
                g.gate_type = item.type;
                g.x = item.x;
                g.y = item.y;
                g.w = item.w;
                g.h = item.h;
                g.inputs = new List<string>();
                if (item.inputs.Count < 1)
                {
                    System.Windows.Forms.MessageBox.Show("Špatný počet vstupu hradela");
                    return;
                }
                if (item.inputs.Count != 1 && item.type.ToLower() == "not")
                {
                    System.Windows.Forms.MessageBox.Show("Špatný počet vstupu hradela");
                    return;
                }
                if(item.outputs.Count!=1&&item.type.Length<=3)
                {
                    System.Windows.Forms.MessageBox.Show("Špatný počet výstupních portu u nějakého hradla");
                    return;
                }
                foreach (var inp in item.inputs)
                {
                    g.inputs.Add(inp.id);
                    if (lines.ContainsKey(inp.id))
                    {
                        lines[inp.id].outputs.Add(g);
                    }
                    else
                    {
                        line l = new line();
                        l.outputs = new List<p_object>();
                        l.outputs.Add(g);
                        lines.Add(inp.id, l);
                    }
                }
                g.outputs = new List<string>();
                foreach (var outp in item.outputs)
                {
                    g.outputs.Add(outp.id);
                    if (lines.ContainsKey(outp.id))
                    {
                    }
                    else
                    {
                        line l = new line();
                        l.outputs = new List<p_object>();
                        lines.Add(outp.id, l);
                    }
                }
                g.dispi = item.inputs;
                g.dispo = item.outputs;
                gates.Add(g);
                if (item.x > max_x)
                    max_x = item.x;
                if (item.y > max_y)
                    max_y = item.y;
            }
        }
        public Hradla h;
        public bool Step()
        {
            foreach (var item in gates)
            {
                bool can = true;
                foreach (var inp in item.inputs)
                {
                    if (lines[inp].state == 2)
                        can = false;
                }
                if (can)
                {
                    int result;
                    switch (item.gate_type.ToLower())
                    {
                        case "not":
                            if (lines[item.inputs[0]].state == 1)
                                lines[item.outputs[0]].state = 0;
                            else
                                lines[item.outputs[0]].state = 1;
                            break;
                        case "and":
                            result = 1;
                            foreach (var inp in item.inputs)
                            {
                                if (lines[inp].state != 1)
                                {
                                    result = 0;
                                    break;
                                }
                            }
                            lines[item.outputs[0]].state = result;
                            break;
                        case "or":
                            result = 0;
                            foreach (var inp in item.inputs)
                            {
                                if (lines[inp].state == 1)
                                {
                                    result = 1;
                                    break;
                                }
                            }
                            lines[item.outputs[0]].state = result;
                            break;
                        case "xor":
                            result = 0;
                            foreach (var inp in item.inputs)
                            {
                                if (lines[inp].state == 1)
                                {
                                    result++;
                                }
                            }
                            lines[item.outputs[0]].state = (result % 2);  
                            break;
                        default:
                            //VNORENE HRADLO
                            //JA BYCH SPIS REK ZE FPGA
                            h.Load(item.gate_type);
                            List<int> inputs = new List<int>();
                            foreach (var input in item.inputs)
                            {
                                inputs.Add(lines[input].state);
                            }
                            int[] data = h.CallFPGA(inputs.ToArray(), item.gate_type);
                            result = 0;//tady jako počítadlo
                            foreach (var outp in item.outputs)
                            {
                                lines[outp].state = data[result];
                                result++;
                            }
                            break;
                    }
                    foreach (var idout in item.outputs)
                    {
                        if (lines[idout].output && lines[idout].state != 2)
                        {
                            lines[idout].output = false;
                            out_done++;
                        }
                    }
                }
            }
            if (out_done > outputs.Count)
                return true;
            else
                return false;
        }
        public void Reset()
        {
            foreach (var item in lines)
            {
                item.Value.state = 2;
            }
            out_done = 0;
        }
    }
    public class p_object
    {
        public int x;
        public int y;
        public int h;
        public int w;
    }
    public class gat : p_object
    {
        public string gate_type;
        public List<string> inputs;
        public List<string> outputs;
        public List<input> dispi;
        public List<output> dispo;
    }
    public class io : p_object
    {
        public string linename;
    }
    public class line
    {
        public List<p_object> outputs = new List<p_object>();
        public int state=2;
        public bool output=false;
    }
}