private AutomataDefinition(Neighbourhood neighbourhood, bool wrap, StateDefinition[] states)
 {
     NumStates = states.Length;
     Neighbourhood = neighbourhood;
     Wrap = wrap;
     States = states;
 }
        public static AutomataDefinition Create(string formula, out string error)
        {
            error = string.Empty;

            if(string.IsNullOrWhiteSpace(formula))
            {
                error = "Formula cannot be empty.";
                return null;
            }

            List<StateDefinition> states = new List<StateDefinition>();
            List<StateRule> rules = new List<StateRule>();

            string[] lines = formula.Split('|','\n','\r');

            Neighbourhood neighbourhood = Neighbourhood.Moore;
            bool wrap = false;

            foreach(var line in lines)
            {
                string parse = line.Replace(" ", string.Empty);
                parse = parse.Replace("\t", string.Empty);
                parse = parse.ToLowerInvariant();

                if(parse == "n")
                {
                    neighbourhood = Neighbourhood.VonNeumann;
                    continue;
                }

                if (parse == "m")
                {
                    neighbourhood = Neighbourhood.Moore;
                    continue;
                }

                if (parse == "w")
                {
                    wrap = true;
                    continue;
                }

                if (parse == "b")
                {
                    wrap = false;
                    continue;
                }

                string[] pair = parse.Split(':');

                if(pair.Length != 2)
                {
                    error = "Syntax error: '" + line + "'.";
                    return null;
                }

                byte state = 0;
                if(!byte.TryParse(pair[0], out state) || state > 15)
                {
                    error = "Syntax error: '" + line + "'. Expected number between 0 and 15.";
                    return null;
                }

                string[] newStates = pair[1].Split(',');

                rules.Clear();

                foreach(var rule in newStates)
                {
                    byte stateId = 0;
                    byte count = StateRule.AnyCount;

                    if(rule.Contains('('))
                    {
                        string[] exp = rule.Split('(', ')');

                        if (!byte.TryParse(exp[0], out stateId) || stateId > 15)
                        {
                            error = "Syntax error: '" + line + "'. Expected number between 0 and 15.";
                            return null;
                        }

                        if (!byte.TryParse(exp[1], out count) || count > 8)
                        {
                            error = "Syntax error: '" + line + "'. Expected number between 0 and 8.";
                            return null;
                        }
                    }
                    else
                    {
                        if(!byte.TryParse(rule, out stateId) || stateId > 15)
                        {
                            error = "Syntax error: '" + line + "'. Expected number between 0 and 15.";
                            return null;
                        }
                    }

                    if(rules.Find((v)=>(v.State == stateId && v.Count == count)) != null)
                    {
                        error = "Error: '" + line + "'. Already defined state-count pair.";
                        return null;
                    }

                    if (count == StateRule.AnyCount && rules.Find((v) => (v.Count == count)) != null)
                    {
                        error = "Error: '" + line + "'. Already defined default state.";
                        return null;
                    }

                    rules.Add(new StateRule(stateId, count));
                }

                if(states.Find(v=>v.State == state)!=null)
                {
                    error = string.Format("Error: '{0}'. Already defined state {1}.", line, state);
                    return null;
                }

                StateDefinition stateDefinition = new StateDefinition(state, rules.ToArray());
                states.Add(stateDefinition);
            }

            states.Sort((v1, v2) =>
                {
                    return Math.Sign(v1.State - v2.State);
                });

            for (int idx = 0; idx < states.Count; ++idx )
            {
                  if(states[idx].State != idx)
                  {
                      error = string.Format("Missing state definition: {0}.", idx);
                      return null;
                  }
            }

            //M|0:0|1:2|2:3|3:1(1=1,2),3

            return new AutomataDefinition(neighbourhood, wrap, states.ToArray());
        }