static SqlPreCommand ProcessUserQuery(Replacements replacements, Table table, UserQueryEntity uq)
        {
            try
            {
                Console.Clear();

                SafeConsole.WriteLineColor(ConsoleColor.White, "UserQuery: " + uq.DisplayName);
                Console.WriteLine(" Query: " + uq.Query.Key);

                if (uq.Filters.Any(a => a.Token.ParseException != null) ||
                   uq.Columns.Any(a => a.Token != null && a.Token.ParseException != null) ||
                   uq.Orders.Any(a => a.Token.ParseException != null))
                {

                    QueryDescription qd = DynamicQueryManager.Current.QueryDescription(uq.Query.ToQueryName());

                    if (uq.Filters.Any())
                    {
                        Console.WriteLine(" Filters:");
                        foreach (var item in uq.Filters.ToList())
                        {
                            QueryTokenEntity token = item.Token;
                            switch (QueryTokenSynchronizer.FixToken(replacements, ref token, qd, SubTokensOptions.CanAnyAll | SubTokensOptions.CanElement, "{0} {1}".FormatWith(item.Operation, item.ValueString), allowRemoveToken: true, allowReCreate: false))
                            {
                                case FixTokenResult.Nothing: break;
                                case FixTokenResult.DeleteEntity: return table.DeleteSqlSync(uq);
                                case FixTokenResult.RemoveToken: uq.Filters.Remove(item); break;
                                case FixTokenResult.SkipEntity: return null;
                                case FixTokenResult.Fix: item.Token = token; break;
                                default: break;
                            }
                        }
                    }

                    if (uq.Columns.Any())
                    {
                        Console.WriteLine(" Columns:");
                        foreach (var item in uq.Columns.ToList())
                        {
                            QueryTokenEntity token = item.Token;
                            switch (QueryTokenSynchronizer.FixToken(replacements, ref token, qd, SubTokensOptions.CanElement, item.DisplayName.HasText() ? "'{0}'".FormatWith(item.DisplayName) : null, allowRemoveToken: true, allowReCreate: false))
                            {
                                case FixTokenResult.Nothing: break;
                                case FixTokenResult.DeleteEntity: ; return table.DeleteSqlSync(uq);
                                case FixTokenResult.RemoveToken: uq.Columns.Remove(item); break;
                                case FixTokenResult.SkipEntity: return null;
                                case FixTokenResult.Fix: item.Token = token; break;
                                default: break;
                            }
                        }
                    }

                    if (uq.Orders.Any())
                    {
                        Console.WriteLine(" Orders:");
                        foreach (var item in uq.Orders.ToList())
                        {
                            QueryTokenEntity token = item.Token;
                            switch (QueryTokenSynchronizer.FixToken(replacements, ref token, qd, SubTokensOptions.CanElement, item.OrderType.ToString(), allowRemoveToken: true, allowReCreate: false))
                            {
                                case FixTokenResult.Nothing: break;
                                case FixTokenResult.DeleteEntity: return table.DeleteSqlSync(uq);
                                case FixTokenResult.RemoveToken: uq.Orders.Remove(item); break;
                                case FixTokenResult.SkipEntity: return null;
                                case FixTokenResult.Fix: item.Token = token; break;
                                default: break;
                            }
                        }
                    }
                }

                foreach (var item in uq.Filters.ToList())
                {
                retry:
                    string val = item.ValueString;
                    switch (QueryTokenSynchronizer.FixValue(replacements, item.Token.Token.Type, ref val, allowRemoveToken: true, isList: item.Operation.IsList()))
                    {
                        case FixTokenResult.Nothing: break;
                        case FixTokenResult.DeleteEntity: return table.DeleteSqlSync(uq);
                        case FixTokenResult.RemoveToken: uq.Filters.Remove(item); break;
                        case FixTokenResult.SkipEntity: return null;
                        case FixTokenResult.Fix: item.ValueString = val; goto retry;
                    }
                }

                if (uq.WithoutFilters)
                    uq.Filters.Clear();

                if (!uq.ShouldHaveElements && uq.ElementsPerPage.HasValue)
                    uq.ElementsPerPage = null;

                if (uq.ShouldHaveElements && !uq.ElementsPerPage.HasValue)
                    uq.ElementsPerPage = 20;

                Console.Clear();

                using (replacements.WithReplacedDatabaseName())
                    return table.UpdateSqlSync(uq, includeCollections: true);
            }
            catch (Exception e)
            {
                return new SqlPreCommandSimple("-- Exception in {0}: {1}".FormatWith(uq.BaseToString(), e.Message));
            }
        }
        private static SqlPreCommand SyncEnums(Schema schema, Table table, Dictionary<string, Entity> current, Dictionary<string, Entity> should)
        {
            var deletes = Synchronizer.SynchronizeScript(
                       should,
                       current,
                       null,
                       (str, c) => table.DeleteSqlSync(c, comment: c.toStr),
                       null, Spacing.Double);

            var moves = Synchronizer.SynchronizeScript(
                       should,
                       current,
                       null,
                       null,
                       (str, s, c) =>
                       {
                           if (s.id == c.id)
                               return table.UpdateSqlSync(c, comment: c.toStr);

                           var insert = table.InsertSqlSync(s);

                           var move = (from t in schema.GetDatabaseTables()
                                       from col in t.Columns.Values
                                       where col.ReferenceTable == table
                                       select new SqlPreCommandSimple("UPDATE {0} SET {1} = {2} WHERE {1} = {3} -- {4} re-indexed"
                                           .FormatWith(t.Name, col.Name, s.Id, c.Id, c.toStr)))
                                        .Combine(Spacing.Simple);

                           var delete = table.DeleteSqlSync(c, comment: c.toStr);

                           return SqlPreCommand.Combine(Spacing.Simple, insert, move, delete);
                       }, Spacing.Double);

            var creates = Synchronizer.SynchronizeScript(
                   should,
                   current,
                  (str, s) => table.InsertSqlSync(s),
                   null,
                   null, Spacing.Double);

            return SqlPreCommand.Combine(Spacing.Double, deletes, moves, creates);
        }
        internal static SqlPreCommand Regenerate(EmailTemplateEntity et, Replacements replacements, Table table)
        {
            var newTemplate = SystemEmailLogic.CreateDefaultTemplate(et.SystemEmail);

            newTemplate.SetId(et.IdOrNull);
            newTemplate.SetNew(false);
            newTemplate.Ticks = et.Ticks; 

            using (replacements == null ? null : replacements.WithReplacedDatabaseName())
                return table.UpdateSqlSync(newTemplate, includeCollections: true, comment: "EmailTemplate Regenerated: " + et.Name);
        }
        static SqlPreCommand ProcessUserChart(Replacements replacements, Table table, UserChartEntity uc)
        {
            try
            {
                Console.Clear();

                SafeConsole.WriteLineColor(ConsoleColor.White, "UserChart: " + uc.DisplayName);
                Console.WriteLine(" ChartScript: " + uc.ChartScript.ToString());
                Console.WriteLine(" Query: " + uc.Query.Key);

                if (uc.Filters.Any(a => a.Token.ParseException != null) ||
                   uc.Columns.Any(a => a.Token != null && a.Token.ParseException != null) ||
                   uc.Orders.Any(a => a.Token.ParseException != null))
                {
                    QueryDescription qd = DynamicQueryManager.Current.QueryDescription(uc.Query.ToQueryName());

                    SubTokensOptions canAggregate = uc.GroupResults ? SubTokensOptions.CanAggregate : 0;

                    if (uc.Filters.Any())
                    {
                        Console.WriteLine(" Filters:");
                        foreach (var item in uc.Filters.ToList())
                        {
                            QueryTokenEntity token = item.Token;
                            switch (QueryTokenSynchronizer.FixToken(replacements, ref token, qd, SubTokensOptions.CanAnyAll | SubTokensOptions.CanElement | canAggregate, "{0} {1}".FormatWith(item.Operation, item.ValueString), allowRemoveToken: true, allowReCreate: false))
                            {
                                case FixTokenResult.Nothing: break;
                                case FixTokenResult.DeleteEntity: return table.DeleteSqlSync(uc);
                                case FixTokenResult.RemoveToken: uc.Filters.Remove(item); break;
                                case FixTokenResult.SkipEntity: return null;
                                case FixTokenResult.Fix: item.Token = token; break;
                                default: break;
                            }
                        }
                    }

                    if (uc.Columns.Any())
                    {
                        Console.WriteLine(" Columns:");
                        foreach (var item in uc.Columns.ToList())
                        {
                            QueryTokenEntity token = item.Token;
                            if (item.Token == null)
                                break;

                            switch (QueryTokenSynchronizer.FixToken(replacements, ref token, qd, SubTokensOptions.CanElement | canAggregate, item.ScriptColumn.DisplayName, allowRemoveToken: item.ScriptColumn.IsOptional, allowReCreate: false))
                            {
                                case FixTokenResult.Nothing: break;
                                case FixTokenResult.DeleteEntity: return table.DeleteSqlSync(uc);
                                case FixTokenResult.RemoveToken: item.Token = null; break;
                                case FixTokenResult.SkipEntity: return null;
                                case FixTokenResult.Fix: item.Token = token; break;
                                default: break;
                            }
                        }
                    }

                    if (uc.Orders.Any())
                    {
                        Console.WriteLine(" Orders:");
                        foreach (var item in uc.Orders.ToList())
                        {
                            QueryTokenEntity token = item.Token;
                            switch (QueryTokenSynchronizer.FixToken(replacements, ref token, qd, SubTokensOptions.CanElement | canAggregate, item.OrderType.ToString(), allowRemoveToken: true, allowReCreate: false))
                            {
                                case FixTokenResult.Nothing: break;
                                case FixTokenResult.DeleteEntity: return table.DeleteSqlSync(uc);
                                case FixTokenResult.RemoveToken: uc.Orders.Remove(item); break;
                                case FixTokenResult.SkipEntity: return null;
                                case FixTokenResult.Fix: item.Token = token; break;
                                default: break;
                            }
                        }
                    }
                }

                foreach (var item in uc.Filters.ToList())
                {
                    string val = item.ValueString;
                    switch (QueryTokenSynchronizer.FixValue(replacements, item.Token.Token.Type, ref val, allowRemoveToken: true, isList: item.Operation == FilterOperation.IsIn))
                    {
                        case FixTokenResult.Nothing: break;
                        case FixTokenResult.DeleteEntity: return table.DeleteSqlSync(uc);
                        case FixTokenResult.RemoveToken: uc.Filters.Remove(item); break;
                        case FixTokenResult.SkipEntity: return null;
                        case FixTokenResult.Fix: item.ValueString = val; break;
                    }
                }

                foreach (var item in uc.Columns)
                {
                    uc.FixParameters(item);
                }


                try
                {
                    return table.UpdateSqlSync(uc, includeCollections: true);
                }
                catch(Exception e)
                {
                    Console.WriteLine("Integrity Error:");
                    SafeConsole.WriteLineColor(ConsoleColor.DarkRed, e.Message);
                    while (true)
                    {
                        SafeConsole.WriteLineColor(ConsoleColor.Yellow, "- s: Skip entity");
                        SafeConsole.WriteLineColor(ConsoleColor.Red, "- d: Delete entity");

                        string answer = Console.ReadLine();

                        if (answer == null)
                            throw new InvalidOperationException("Impossible to synchronize interactively without Console");

                        answer = answer.ToLower();

                        if (answer == "s")
                            return null;

                        if (answer == "d")
                            return table.DeleteSqlSync(uc);
                    }
                }

               
            }
            catch (Exception e)
            {
                return new SqlPreCommandSimple("-- Exception in {0}: {1}".FormatWith(uc.BaseToString(), e.Message));
            }
            finally
            {
                Console.Clear();
            }
        }
        internal static SqlPreCommand ProcessEmailTemplate( Replacements replacements, Table table, EmailTemplateEntity et, StringDistance sd)
        {
            try
            {
                var queryName = QueryLogic.ToQueryName(et.Query.Key);

                QueryDescription qd = DynamicQueryManager.Current.QueryDescription(queryName);

                Console.Clear();

                SafeConsole.WriteLineColor(ConsoleColor.White, "EmailTemplate: " + et.Name);
                Console.WriteLine(" Query: " + et.Query.Key);

                if (et.From != null && et.From.Token != null)
                {
                    QueryTokenEntity token = et.From.Token;
                    switch (QueryTokenSynchronizer.FixToken(replacements, ref token, qd, SubTokensOptions.CanElement, " From", allowRemoveToken: false, allowReCreate: et.SystemEmail != null))
                    {
                        case FixTokenResult.Nothing: break;
                        case FixTokenResult.DeleteEntity: return table.DeleteSqlSync(et);
                        case FixTokenResult.SkipEntity: return null;
                        case FixTokenResult.Fix: et.From.Token = token; break;
                        case FixTokenResult.ReGenerateEntity: return Regenerate(et, replacements, table);
                        default: break;
                    }
                }

                if (et.Recipients.Any(a=>a.Token != null))
                {
                    Console.WriteLine(" Recipients:");
                    foreach (var item in et.Recipients.Where(a => a.Token != null).ToList())
                    {
                        QueryTokenEntity token = item.Token;
                        switch (QueryTokenSynchronizer.FixToken(replacements, ref token, qd, SubTokensOptions.CanElement, " Recipient", allowRemoveToken: false, allowReCreate: et.SystemEmail != null))
                        {
                            case FixTokenResult.Nothing: break;
                            case FixTokenResult.DeleteEntity: return table.DeleteSqlSync(et);
                            case FixTokenResult.RemoveToken: et.Recipients.Remove(item); break;
                            case FixTokenResult.SkipEntity: return null;
                            case FixTokenResult.Fix: item.Token = token; break;
                            case FixTokenResult.ReGenerateEntity: return Regenerate(et, replacements, table);
                            default: break;
                        }
                    }
                }

                try
                {

                    foreach (var item in et.Messages)
                    {
                        SyncronizationContext sc = new SyncronizationContext
                        {
                            ModelType = et.SystemEmail.ToType(),
                            QueryDescription = qd,
                            Replacements = replacements,
                            StringDistance = sd,
                            Variables = new ScopedDictionary<string, ValueProviderBase>(null)
                        };

                        item.Subject = Synchronize(item.Subject, sc);
                        item.Text = Synchronize(item.Text, sc);
                    }

                    using (replacements.WithReplacedDatabaseName())
                        return table.UpdateSqlSync(et, includeCollections: true, comment: "EmailTemplate: " + et.Name);
                }
                catch (TemplateSyncException ex)
                {
                    if (ex.Result == FixTokenResult.SkipEntity)
                        return null;

                    if (ex.Result == FixTokenResult.DeleteEntity)
                        return table.DeleteSqlSync(et);

                    if (ex.Result == FixTokenResult.ReGenerateEntity)
                        return Regenerate(et, replacements, table);

                    throw new InvalidOperationException("Unexcpected {0}".FormatWith(ex.Result));
                }
                finally
                {
                    Console.Clear();
                }
            }
            catch (Exception e)
            {
                return new SqlPreCommandSimple("-- Exception in {0}: {1}".FormatWith(et.BaseToString(), e.Message));
            }
        }