コード例 #1
0
        internal async Task <WorkPreview> PreviewAsync(IPrinter printer)
        {
            void PrintSide(ISideRunner si)
            {
                printer.Foreach($"Side '{si.Definition.Name}' {(si.Definition.IsMaster ? "(MASTER)" : "")}:", si.SubSides, s => PrintSide(s));
            }

            using (printer.Indent($"Work '{Definition.Name}'"))
            {
                // Get master side
                var masters = Sides.Where(s => s.Definition.IsMaster);
                if (masters.Count() != 1)
                {
                    throw new ArgumentException($"One, and only one '{nameof(ISide)}' must be the master side");
                }
                MasterSide = masters.Single();

                // Determine what sides are sub-sides of others
                void PopulateSubSides(ISideRunner side)
                {
                    side.SubSides = Sides.Where(s => s.GetSourceType() == side.GetItemType()).ToList();
                    foreach (var s in side.SubSides)
                    {
                        if (side.Definition.IsMaster)
                        {
                            s.Definition.IsMaster = true;
                        }
                        PopulateSubSides(s);
                    }
                }

                var rootSides = Sides.Where(s => !Sides.Any(s2 => s2.GetItemType() == s.GetSourceType())).OrderByDescending(s => s.Definition.IsMaster).ThenBy(s => s.Definition.Name).ToList();
                foreach (var side in rootSides)
                {
                    PopulateSubSides(side);
                }
                printer.Foreach("Sides tree:", rootSides, side =>
                {
                    PrintSide(side);
                });

                // Search for comparators for any side with master side
                void SearchComparator(ISideRunner side)
                {
                    var cc = Comparators.Where(c =>
                    {
                        var mts = MasterSide.GetAllItemsType();
                        var st  = side.GetItemType();
                        var ct  = c.GetItemTypes();
                        return((mts.Contains(ct.Item1) && ct.Item2 == st) || (mts.Contains(ct.Item2) && ct.Item1 == st));
                    }).Cast <IComparatorRunner>();

                    if (cc.Count() != 1)
                    {
                        throw new ArgumentException($"One, and only one '{nameof(ISide)}' must be added for master side '{MasterSide.Definition.Name}' and each side");
                    }
                    side.Comparator = cc.Single();
                    printer.WriteLine($"Comparator for side '{side.Definition.Name}' is '{side.Comparator.GetItemTypes().Item1.Name}' <> '{side.Comparator.GetItemTypes().Item2.Name}'");
                    foreach (var subSide in side.SubSides)
                    {
                        Sides.Where(s => s.GetSourceType() == subSide.GetItemType());
                        SearchComparator(subSide);
                    }
                }

                // Iterate non master sides to search for a comparator for they
                printer.Foreach("Comparators: ", rootSides.Where(s => !s.Definition.IsMaster), side => SearchComparator(side));

                // Load sides
                using (printer.Indent($"Loading sides {(Definition.LoadSidesInParallel ? "in parallel" : "sequentially")} ..."))
                {
                    if (Definition.LoadSidesInParallel)
                    {
                        await Task.WhenAll(rootSides.Select(s => s.Load()));
                    }
                    else
                    {
                        await TaskManager.StartNew(async() =>
                        {
                            foreach (var side in rootSides)
                            {
                                await side.Load();
                            }
                        });
                    }
                }

                // Comparing sides
                printer.Foreach("Comparing each side with master side ...", rootSides.Where(s => !s.Definition.IsMaster), sid => {
                    if (sid.Comparator.GetItemTypes().Item1 == MasterSide.GetItemType())
                    {
                        // Master is A in this comparer
                        sid.Results = sid.Comparator.CompareSides(MasterSide, sid, false, printer);
                    }
                    else
                    {
                        // Master is B in this comparer
                        sid.Results = sid.Comparator.CompareSides(sid, MasterSide, true, printer);
                    }
                });
                printer.WriteLine("Analyzing results ...");
                ICollection <IItemRunner> AnalyzeResults(ICollection <ISideRunner> sides)
                {
                    var res = new List <IItemRunner>();

                    // Group side results by item key and populate with sides results
                    foreach (var gro in sides
                             .SelectMany(side => side.Results.Select(result => new
                    {
                        Key = result.Key,
                        MasterRunner = side.SearchMasterSubSide(MasterSide),
                        MasterItemType = side.SearchMasterSubSide(MasterSide).GetItemType(),
                        MasterItem = result.MasterItem,
                        MasterItemName = side.SearchMasterSubSide(MasterSide).GetItemName(result.MasterItem),
                        MasterItemTag = side.SearchMasterSubSide(MasterSide).GetItemTag(result.MasterItem),
                        //SideId = side.Id,
                        Side = side,
                        SideItemType = side.GetItemType(),
                        SideItem = result.SideItem,
                        SideItemName = side.GetItemName(result.SideItem),
                        SideItemTag = side.GetItemTag(result.SideItem),
                        SideName = side.Definition.Name,
                        SideSubSides = result.SubSides,
                        Properties = result.Properties.ToArray()
                    }))
                             .GroupBy(r => r.Key))
                    {
                        // Create item
                        var fir      = gro.First(); // Use first element to get master info, all items in this group has the same master item
                        var itemType = typeof(ItemRunner <>).MakeGenericType(fir.MasterItemType);
                        var item     = (IItemRunner)Activator.CreateInstance(itemType, fir.MasterRunner, fir.MasterItem, fir.MasterItemName, fir.MasterItemTag);
                        foreach (var i in gro)
                        {
                            // Create side
                            var sideItemType = typeof(ItemSideRunner <,>).MakeGenericType(i.SideItemType, i.Key.GetType());
                            var sideItem     = (IItemSideRunner)Activator.CreateInstance(sideItemType, i.Side, i.SideName, i.Key, i.SideItem, i.SideItemName, i.SideItemTag);
                            foreach (var pro in i.Properties)
                            {
                                ((IList <IPropertyRunner>)sideItem.Properties).Add(pro);
                            }
                            sideItem.SubItems = AnalyzeResults(i.SideSubSides);
                            // Add side to item
                            ((IList <IItemSideRunner>)item.SideRunners).Add(sideItem);
                        }
                        // Add item to work
                        res.Add(item);
                    }
                    return(res);
                }

                foreach (var item in AnalyzeResults(rootSides.Where(side => !side.Definition.IsMaster).ToList()))
                {
                    Items.Add(item);
                }

                // Create preview response
                printer.WriteLine("Creating preview result ...");
                var preWork = new WorkPreview(Definition.Id);
                preWork.Name           = Definition.Name;
                preWork.MasterSideName = MasterSide.Definition.Name;
                var preItems = new List <ItemPreview>();
                foreach (var item in Items)
                {
                    var preItem = new ItemPreview(preWork, item.Id);
                    preItem.MasterItemExist        = item.MasterItem != null;
                    preItem.MasterItemName         = item.MasterItemName;
                    preItem.MasterItemTag          = item.MasterItemTag;
                    preItem.SingularMasterTypeName = MasterSide.Definition.SingularItemTypeName;
                    preItem.PluralMasterTypeName   = MasterSide.Definition.PluralItemTypeName;
                    preItem.MasterTypeIsMale       = MasterSide.Definition.ItemTypeIsMale;

                    var preSides = new List <ItemSidePreview>();
                    foreach (var side in item.SideRunners)
                    {
                        var preSide = new ItemSidePreview(preItem, side.Side.Id);
                        preSide.Key                  = side.Key.ToString();
                        preSide.SideAllowInsert      = side.Side.Definition.AllowInsert;
                        preSide.SideAllowDelete      = side.Side.Definition.AllowDelete;
                        preSide.SideAllowUpdate      = side.Side.Definition.AllowUpdate;
                        preSide.SideItemExist        = side.SideItem != null;
                        preSide.SideItemName         = side.SideItemName;
                        preSide.SideItemTag          = side.SideItemTag;
                        preSide.SingularSideTypeName = side.Side.Definition.SingularItemTypeName;
                        preSide.PluralSideTypeName   = side.Side.Definition.PluralItemTypeName;
                        preSide.ItemTypeIsMale       = side.Side.Definition.ItemTypeIsMale;
                        preSide.SideName             = side.Name;
                        foreach (var pro in side.Properties)
                        {
                            var prePro = new PropertyPreview(preSide);
                            prePro.MasterValue  = pro.MasterNamingFunction(pro.MasterValue);
                            prePro.SideValue    = pro.SideNamingFunction(pro.SideValue);
                            prePro.PropertyName = pro.PropertyName;
                            preSide.Properties.Add(prePro);
                        }
                        ICollection <ItemRelationPreview> ProcessSubItems(object parent, ICollection <IItemRunner> items)
                        {
                            var res = new List <ItemRelationPreview>();

                            foreach (var i in items)
                            {
                                ItemRelationPreview rel;
                                if (parent is ItemSidePreview)
                                {
                                    rel = new ItemRelationPreview(parent as ItemSidePreview, i.Id);
                                }
                                else
                                {
                                    rel = new ItemRelationPreview(parent as ItemRelationPreview, i.Id);
                                }
                                rel.SideAllowInsert        = i.SideRunners.Single().Side.Definition.AllowInsert;
                                rel.SideAllowDelete        = i.SideRunners.Single().Side.Definition.AllowDelete;
                                rel.SideAllowUpdate        = i.SideRunners.Single().Side.Definition.AllowUpdate;
                                rel.MasterItemExist        = i.MasterItem != null;
                                rel.MasterItemName         = i.MasterItemName;
                                rel.MasterItemTag          = i.MasterItemTag;
                                rel.SingularMasterTypeName = i.MasterRunner.Definition.SingularItemTypeName;
                                rel.PluralMasterTypeName   = i.MasterRunner.Definition.PluralItemTypeName;
                                rel.SingularSideTypeName   = i.SideRunners.Single().Side.Definition.SingularItemTypeName;
                                rel.PluralSideTypeName     = i.SideRunners.Single().Side.Definition.PluralItemTypeName;
                                var subSide = i.SideRunners.Single();
                                rel.Key           = subSide.Key.ToString();
                                rel.SideItemExist = subSide.SideItem != null;
                                rel.SideItemName  = subSide.SideItemName;
                                rel.SideItemTag   = subSide.SideItemTag;
                                rel.SideName      = subSide.Name;
                                foreach (var pro in subSide.Properties)
                                {
                                    var prePro = new PropertyPreview(rel);
                                    prePro.MasterValue  = pro.MasterNamingFunction(pro.MasterValue);
                                    prePro.SideValue    = pro.SideNamingFunction(pro.SideValue);
                                    prePro.PropertyName = pro.PropertyName;
                                    rel.Properties.Add(prePro);
                                }
                                rel.Relations = ProcessSubItems(rel, subSide.SubItems);
                                res.Add(rel);
                            }
                            return(res);
                        }

                        preSide.Relations = ProcessSubItems(preSide, side.SubItems);
                        preSides.Add(preSide);
                    }
                    preItem.Sides = preSides;
                    preItems.Add(preItem);
                }
                preWork.Items = preItems;

                // Check result and suggest an action
                printer.WriteLine("Determining default actions ...");
                foreach (var item in preWork.Items)
                {
                    foreach (var side in item.Sides)
                    {
                        if (!item.MasterItemExist && side.SideAllowDelete)
                        {
                            side.Action = SynchronizationAction.Delete;
                        }
                        else if (!side.SideItemExist && side.SideAllowInsert)
                        {
                            side.Action = SynchronizationAction.Insert;
                        }
                        else if (side.Properties.Count() > 0 && side.SideAllowUpdate)
                        {
                            side.Action = SynchronizationAction.Update;
                        }
                        void ProcessRelations(ICollection <ItemRelationPreview> relations)
                        {
                            foreach (var rel in relations)
                            {
                                if (!rel.MasterItemExist && rel.SideAllowDelete)
                                {
                                    rel.Action = SynchronizationAction.Delete;
                                }
                                else if (!rel.SideItemExist && rel.SideAllowInsert)
                                {
                                    rel.Action = SynchronizationAction.Insert;
                                }
                                else if (rel.Properties.Count() > 0 && rel.SideAllowUpdate)
                                {
                                    rel.Action = SynchronizationAction.Update;
                                }
                                ProcessRelations(rel.Relations);
                            }
                        }

                        ProcessRelations(side.Relations);
                    }
                }
                return(preWork);
            }
            //return printer.IndentAsync($"Work '{Definition.Name}'", async () =>
            //{
            //    // Get master side
            //    var masters = Sides.Where(s => s.Definition.IsMaster);
            //    if (masters.Count() != 1) throw new ArgumentException($"One, and only one '{nameof(ISide)}' must be the master side");
            //    MasterSide = masters.Single();

            //    // Determine what sides are sub-sides of others
            //    void PopulateSubSides(ISideRunner side)
            //    {
            //        side.SubSides = Sides.Where(s => s.GetSourceType() == side.GetItemType()).ToList();
            //        foreach (var s in side.SubSides)
            //        {
            //            if (side.Definition.IsMaster) s.Definition.IsMaster = true;
            //            PopulateSubSides(s);
            //        }
            //    }
            //    var rootSides = Sides.Where(s => !Sides.Any(s2 => s2.GetItemType() == s.GetSourceType())).OrderByDescending(s => s.Definition.IsMaster).ThenBy(s => s.Definition.Name).ToList();
            //    foreach (var side in rootSides)
            //        PopulateSubSides(side);
            //    printer.Foreach("Sides tree:", rootSides, side =>
            //    {
            //        PrintSide(side);
            //    });

            //    // Search for comparators for any side with master side
            //    void SearchComparator(ISideRunner side)
            //    {
            //        var cc = Comparators.Where(c =>
            //        {
            //            var mts = MasterSide.GetAllItemsType();
            //            var st = side.GetItemType();
            //            var ct = c.GetItemTypes();
            //            return (mts.Contains(ct.Item1) && ct.Item2 == st) || (mts.Contains(ct.Item2) && ct.Item1 == st);
            //        }).Cast<IComparatorRunner>();
            //        if (cc.Count() != 1) throw new ArgumentException($"One, and only one '{nameof(ISide)}' must be added for master side '{MasterSide.Definition.Name}' and each side");
            //        side.Comparator = cc.Single();
            //        printer.WriteLine($"Comparator for side '{side.Definition.Name}' is '{side.Comparator.GetItemTypes().Item1.Name}' <> '{side.Comparator.GetItemTypes().Item2.Name}'");
            //        foreach (var subSide in side.SubSides)
            //        {
            //            Sides.Where(s => s.GetSourceType() == subSide.GetItemType());
            //            SearchComparator(subSide);
            //        }
            //    }
            //    // Iterate non master sides to search for a comparator for they
            //    printer.Foreach("Comparators: ", rootSides.Where(s => !s.Definition.IsMaster), side => SearchComparator(side));

            //    // Load sides
            //    await printer.IndentAsync($"Loading sides {(Definition.LoadSidesInParallel ? "in parallel" : "sequentially")} ...", () =>
            //    {
            //        if (Definition.LoadSidesInParallel)
            //        {
            //            return Task.WhenAll(rootSides.Select(s => s.Load()));
            //        }else
            //        {
            //            return TaskManager.StartNew(async () =>
            //            {
            //                foreach (var side in rootSides)
            //                {
            //                    await side.Load();
            //                }
            //            });
            //        }
            //    });

            //    // Comparing sides
            //    printer.Foreach("Comparing each side with master side ...", rootSides.Where(s => !s.Definition.IsMaster), sid=> {
            //        if (sid.Comparator.GetItemTypes().Item1 == MasterSide.GetItemType())
            //        {
            //            // Master is A in this comparer
            //            sid.Results = sid.Comparator.CompareSides(MasterSide, sid, false, printer);
            //        }
            //        else
            //        {
            //            // Master is B in this comparer
            //            sid.Results = sid.Comparator.CompareSides(sid, MasterSide, true, printer);
            //        }
            //    });
            //    printer.WriteLine("Analyzing results ...");
            //    ICollection<IItemRunner> AnalyzeResults(ICollection<ISideRunner> sides)
            //    {
            //        var res = new List<IItemRunner>();
            //        // Group side results by item key and populate with sides results
            //        foreach (var gro in sides
            //            .SelectMany(side => side.Results.Select(result => new
            //            {
            //                Key = result.Key,
            //                MasterRunner = side.SearchMasterSubSide(MasterSide),
            //                MasterItemType = side.SearchMasterSubSide(MasterSide).GetItemType(),
            //                MasterItem = result.MasterItem,
            //                MasterItemName = side.SearchMasterSubSide(MasterSide).GetItemName(result.MasterItem),
            //                MasterItemTag = side.SearchMasterSubSide(MasterSide).GetItemTag(result.MasterItem),
            //                //SideId = side.Id,
            //                Side = side,
            //                SideItemType = side.GetItemType(),
            //                SideItem = result.SideItem,
            //                SideItemName = side.GetItemName(result.SideItem),
            //                SideItemTag = side.GetItemTag(result.SideItem),
            //                SideName = side.Definition.Name,
            //                SideSubSides = result.SubSides,
            //                Properties = result.Properties.ToArray()
            //            }))
            //            .GroupBy(r => r.Key))
            //        {
            //            // Create item
            //            var fir = gro.First(); // Use first element to get master info, all items in this group has the same master item
            //            var itemType = typeof(ItemRunner<>).MakeGenericType(fir.MasterItemType);
            //            var item = (IItemRunner)Activator.CreateInstance(itemType, fir.MasterRunner, fir.MasterItem, fir.MasterItemName, fir.MasterItemTag);
            //            foreach (var i in gro)
            //            {
            //                // Create side
            //                var sideItemType = typeof(ItemSideRunner<,>).MakeGenericType(i.SideItemType, i.Key.GetType());
            //                var sideItem = (IItemSideRunner)Activator.CreateInstance(sideItemType, i.Side, i.SideName, i.Key, i.SideItem, i.SideItemName, i.SideItemTag);
            //                foreach (var pro in i.Properties)
            //                    ((IList<IPropertyRunner>)sideItem.Properties).Add(pro);
            //                sideItem.SubItems = AnalyzeResults(i.SideSubSides);
            //                // Add side to item
            //                ((IList<IItemSideRunner>)item.SideRunners).Add(sideItem);
            //            }
            //            // Add item to work
            //            res.Add(item);
            //        }
            //        return res;
            //    }
            //    foreach (var item in AnalyzeResults(rootSides.Where(side => !side.Definition.IsMaster).ToList())) Items.Add(item);

            //    // Create preview response
            //    printer.WriteLine("Creating preview result ...");
            //    var preWork = new WorkPreview(Definition.Id);
            //    preWork.Name = Definition.Name;
            //    preWork.MasterSideName = MasterSide.Definition.Name;
            //    var preItems = new List<ItemPreview>();
            //    foreach (var item in Items)
            //    {
            //        var preItem = new ItemPreview(preWork, item.Id);
            //        preItem.MasterItemExist = item.MasterItem != null;
            //        preItem.MasterItemName = item.MasterItemName;
            //        preItem.MasterItemTag = item.MasterItemTag;
            //        preItem.SingularMasterTypeName = MasterSide.Definition.SingularItemTypeName;
            //        preItem.PluralMasterTypeName = MasterSide.Definition.PluralItemTypeName;
            //        preItem.MasterTypeIsMale = MasterSide.Definition.ItemTypeIsMale;

            //        var preSides = new List<ItemSidePreview>();
            //        foreach (var side in item.SideRunners)
            //        {
            //            var preSide = new ItemSidePreview(preItem, side.Side.Id);
            //            preSide.Key = side.Key.ToString();
            //            preSide.SideAllowInsert = side.Side.Definition.AllowInsert;
            //            preSide.SideAllowDelete = side.Side.Definition.AllowDelete;
            //            preSide.SideAllowUpdate = side.Side.Definition.AllowUpdate;
            //            preSide.SideItemExist = side.SideItem != null;
            //            preSide.SideItemName = side.SideItemName;
            //            preSide.SideItemTag = side.SideItemTag;
            //            preSide.SingularSideTypeName = side.Side.Definition.SingularItemTypeName;
            //            preSide.PluralSideTypeName = side.Side.Definition.PluralItemTypeName;
            //            preSide.ItemTypeIsMale = side.Side.Definition.ItemTypeIsMale;
            //            preSide.SideName = side.Name;
            //            foreach (var pro in side.Properties)
            //            {
            //                var prePro = new PropertyPreview(preSide);
            //                prePro.MasterValue = pro.MasterNamingFunction(pro.MasterValue);
            //                prePro.SideValue = pro.SideNamingFunction(pro.SideValue);
            //                prePro.PropertyName = pro.PropertyName;
            //                preSide.Properties.Add(prePro);
            //            }
            //            ICollection<ItemRelationPreview> ProcessSubItems(object parent, ICollection<IItemRunner> items)
            //            {
            //                var res = new List<ItemRelationPreview>();
            //                foreach (var i in items)
            //                {
            //                    ItemRelationPreview rel;
            //                    if (parent is ItemSidePreview)
            //                        rel = new ItemRelationPreview(parent as ItemSidePreview, i.Id);
            //                    else
            //                        rel = new ItemRelationPreview(parent as ItemRelationPreview, i.Id);
            //                    rel.SideAllowInsert = i.SideRunners.Single().Side.Definition.AllowInsert;
            //                    rel.SideAllowDelete = i.SideRunners.Single().Side.Definition.AllowDelete;
            //                    rel.SideAllowUpdate = i.SideRunners.Single().Side.Definition.AllowUpdate;
            //                    rel.MasterItemExist = i.MasterItem != null;
            //                    rel.MasterItemName = i.MasterItemName;
            //                    rel.MasterItemTag = i.MasterItemTag;
            //                    rel.SingularMasterTypeName = i.MasterRunner.Definition.SingularItemTypeName;
            //                    rel.PluralMasterTypeName = i.MasterRunner.Definition.PluralItemTypeName;
            //                    rel.SingularSideTypeName = i.SideRunners.Single().Side.Definition.SingularItemTypeName;
            //                    rel.PluralSideTypeName = i.SideRunners.Single().Side.Definition.PluralItemTypeName;
            //                    var subSide = i.SideRunners.Single();
            //                    rel.Key = subSide.Key.ToString();
            //                    rel.SideItemExist = subSide.SideItem != null;
            //                    rel.SideItemName = subSide.SideItemName;
            //                    rel.SideItemTag = subSide.SideItemTag;
            //                    rel.SideName = subSide.Name;
            //                    foreach (var pro in subSide.Properties)
            //                    {
            //                        var prePro = new PropertyPreview(rel);
            //                        prePro.MasterValue = pro.MasterNamingFunction(pro.MasterValue);
            //                        prePro.SideValue = pro.SideNamingFunction(pro.SideValue);
            //                        prePro.PropertyName = pro.PropertyName;
            //                        rel.Properties.Add(prePro);
            //                    }
            //                    rel.Relations = ProcessSubItems(rel, subSide.SubItems);
            //                    res.Add(rel);
            //                }
            //                return res;
            //            }
            //            preSide.Relations = ProcessSubItems(preSide, side.SubItems);
            //            preSides.Add(preSide);
            //        }
            //        preItem.Sides = preSides;
            //        preItems.Add(preItem);
            //    }
            //    preWork.Items = preItems;

            //    // Check result and suggest an action
            //    printer.WriteLine("Determining default actions ...");
            //    foreach (var item in preWork.Items)
            //    {
            //        foreach (var side in item.Sides)
            //        {
            //            if (!item.MasterItemExist && side.SideAllowDelete)
            //                side.Action = SynchronizationAction.Delete;
            //            else if (!side.SideItemExist && side.SideAllowInsert)
            //                side.Action = SynchronizationAction.Insert;
            //            else if (side.Properties.Count() > 0 && side.SideAllowUpdate)
            //                side.Action = SynchronizationAction.Update;
            //            void ProcessRelations(ICollection<ItemRelationPreview> relations)
            //            {
            //                foreach (var rel in relations)
            //                {
            //                    if (!rel.MasterItemExist && rel.SideAllowDelete)
            //                        rel.Action = SynchronizationAction.Delete;
            //                    else if (!rel.SideItemExist && rel.SideAllowInsert)
            //                        rel.Action = SynchronizationAction.Insert;
            //                    else if (rel.Properties.Count() > 0 && rel.SideAllowUpdate)
            //                        rel.Action = SynchronizationAction.Update;
            //                    ProcessRelations(rel.Relations);
            //                }
            //            }
            //            ProcessRelations(side.Relations);
            //        }
            //    }
            //    return preWork;
            //});
        }