public override bool Matches(ImportCellMatchContextBase context, string cell)
        {
            // trivial
            if (context == null || cell == null || _separator == null || _sequence == null)
            {
                return(false);
            }

            // try split cell in a sequence
            var cellseq = cell.Split(new[] { _separator }, StringSplitOptions.None);

            if (cellseq.Length == 0)
            {
                // zero is true
                return(true);
            }

            // go as far as we can
            for (int i = 0; i < Math.Min(_sequence.Count, cellseq.Length); i++)
            {
                if (!_sequence[i].Matches(context, cellseq[i]) && !Optional)
                {
                    return(false);
                }
            }

            return(true);
        }
 public override bool Matches(ImportCellMatchContextBase context, string cell)
 {
     return
         (MatchStart && cell.StartsWith(Preset) ||
          MatchContains && cell.Contains(Preset) ||
          cell == Preset);
 }
        public override bool Matches(ImportCellMatchContextBase context, string cell)
        {
            // access
            if (true != context?.IsValid() || cell == null)
            {
                return(false);
            }

            // try break down into pieces
            if (Preset.StartsWith("%Parent.") && Preset.EndsWith("%"))
            {
                return(MatchEntity(context.Parent, Preset.Substring(8, Preset.Length - 9), cell,
                                   ref context.ParentParentName, ref context.ParentElemName, ref context.ParentValue));
            }

            if (Preset.StartsWith("%") && Preset.EndsWith("%") && Preset.Length > 2)
            {
                MatchSpecialCases(context, Preset.Substring(1, Preset.Length - 2), cell);
            }

            if (Preset.StartsWith("%SME.") && Preset.EndsWith("%"))
            {
                return(MatchEntity(context.Sme, Preset.Substring(5, Preset.Length - 6), cell,
                                   ref context.SmeParentName, ref context.SmeElemName, ref context.SmeValue, allowMultiplicity: true));
            }

            if (Preset.StartsWith("%CD.") && Preset.EndsWith("%"))
            {
                return(MatchEntity(context.CD, Preset.Substring(4, Preset.Length - 5), cell));
            }

            // for testing purposes
            return(true);
        }
        //
        // Population
        //

        protected bool CheckMatcherCells(
            IImportTableProvider table,
            ImportCellMatchContextBase context,
            int rowofs,
            List <ImportCellMatcherBase> matcher,
            int matcherRows)
        {
            // access
            if (table == null || matcher == null || matcherRows < 1)
            {
                return(false);
            }

            // over rows?
            if (rowofs + matcherRows > table.MaxRows)
            {
                return(false);
            }

            for (int r = 0; r < matcherRows; r++)
            {
                for (int c = 0; c < _job.Cols; c++)
                {
                    var cell = table.Cell(r + rowofs, c);
                    if (cell == null)
                    {
                        cell = "";
                    }

                    var mi  = (1 + r) * (1 + _job.Cols) + 1 + c;
                    var mat = (mi >= matcher.Count) ? null : matcher[mi];
                    if (mat == null)
                    {
                        _log?.Info($"    invalid matcher at top ({1 + r}, {1 + c})");
                        return(false);
                    }
                    if (!mat.Matches(context, cell))
                    {
                        _log?.Info("{0}", $"    matcher was false ({1 + r}, {1 + c}) " +
                                   $"preset='{mat.Preset}' cell='{cell}'");
                        return(false);
                    }
                }
            }

            // ok
            return(true);
        }
        private void MatchSpecialCases(
            ImportCellMatchContextBase context, string preset, string cell)
        {
            // access
            if (context == null || preset == null || cell == null)
            {
                return;
            }

            // lambda trick to lines of code
            if (preset == "Property.valueType")
            {
                // value type can be distorted in many ways, so commit in each case
                var vt = cell;

                // adopt
                var m = Regex.Match(vt, @"^\s*\[(.*)\]");
                if (m.Success)
                {
                    vt = m.Groups[1].ToString();
                }

                // exclude SMEs
                foreach (var x in AdminShell.SubmodelElementWrapper.AdequateElementNames
                         .Union(AdminShell.SubmodelElementWrapper.AdequateElementShortName))
                {
                    if (x != null && vt.Trim().ToLower() == x.ToLower())
                    {
                        return;
                    }
                }

                // very special case
                if (vt.Trim() == "n/a")
                {
                    return;
                }

                // set
                context.SmeValueType = vt;
            }
        }
 /// <summary>
 /// Checks, if the cell content can be matched by the matcher
 /// </summary>
 public virtual bool Matches(ImportCellMatchContextBase context, string cell)
 {
     return(false);
 }
        public void PopulateBy(IImportTableProvider table)
        {
            // access
            if (!IsValid || table == null || table.MaxRows < 1 || table.MaxCols < 1 ||
                _matcherTop == null || _matcherBody == null)
            {
                return;
            }

            _log?.Info("Starting populating from NEW TABLE");

            // use 2 contexts to collect information during the matching
            var contextTop  = new ImportCellMatchContextBase();
            var contextBody = new ImportCellMatchContextBase();

            // simply scan over potential tops and bodies
            int rowofs          = 0;
            int conseqEmptyRows = 0;

            while (rowofs + _job.RowsTop + _job.RealRowsBody <= table.MaxRows)
            {
                // log
                _log?.Info("{0}", $"  check row {rowofs} starting with {"" + table.Cell(rowofs, 0)} for top ..");

                // first do a evaluation, if the complete row is empty
                if (CheckRowIsEmpty(table, rowofs))
                {
                    // break the full scanning process (using absurd high limit)?
                    conseqEmptyRows++;
                    if (conseqEmptyRows >= 100)
                    {
                        break;
                    }

                    // now, but still empty: take a shortcut to next row
                    rowofs++;
                    continue;
                }
                conseqEmptyRows = 0;

                // top matches?
                contextTop.Clear();
                if (CheckMatcherCells(table, contextTop, rowofs, _matcherTop, _job.RowsTop))
                {
                    // log
                    _log?.Info($"  found matching TOP!");

                    // care for the (containg) top element
                    var refTop = CreateTopReferable(contextTop, actInHierarchy: _job.ActInHierarchy);
                    if (refTop == null)
                    {
                        _log?.Info($"  error creating data for TOP! Skipping!");
                        rowofs++;
                        continue;
                    }

                    // try find elements
                    var rowofs2     = rowofs + _job.RowsTop;
                    var lastGoodRow = rowofs;

                    while (rowofs2 < table.MaxRows)
                    {
                        // log
                        _log?.Info("{0}", $"  check row {rowofs2} starting with " +
                                   $"{"" + table.Cell(rowofs2, 0)} for body ..");

                        // be definition, a completely empty line will break the matching
                        if (CheckRowIsEmpty(table, rowofs2))
                        {
                            break;
                        }

                        // matches
                        contextBody.Clear();
                        if (CheckMatcherCells(table, contextBody, rowofs2, _matcherBody, _job.RowsBody))
                        {
                            // log again
                            _log?.Info($"    found matching BODY as well!");

                            // remember to never visit again
                            lastGoodRow = rowofs2;

                            // an CD with empty identification will cause a new id, therefore
                            // the SME.semanticId will be altered accordingly and will be
                            // written later
                            var cdBody = CreateBodyCD(contextBody, _env);
                            if (cdBody == null)
                            {
                                _log?.Info($"  error creating ConceptDescription for BODY! Skipping!");
                                rowofs2 += _job.RowsBody;
                                continue;
                            }

                            // create SME
                            var refBody = CreateBodySme(contextBody, refTop);
                            if (refBody == null)
                            {
                                _log?.Info($"  error creating SubmodelElement for BODY! Skipping!");
                                rowofs2 += _job.RowsBody;
                                continue;
                            }
                        }

                        // find next row?
                        rowofs2 += _job.RowsBody;
                    }

                    // advance at least to last good row + 1
                    rowofs = lastGoodRow + 1;
                }

                // default
                rowofs++;
            }
        }
        protected ContextResult CreateBodyCD(
            ImportCellMatchContextBase context,
            AdminShell.AdministrationShellEnv env)
        {
            // access
            if (context?.Sme == null || context?.CD == null || env == null || _options == null)
            {
                return(null);
            }

            // first test, if the CD already exists
            var test = env.FindConceptDescription(context.Sme.semanticId);

            if (test != null)
            {
                return new ContextResult()
                       {
                           Elem = test
                       }
            }
            ;

            // a semanticId is required to link the Sme and the CD together
            if (context.Sme.semanticId == null || context.Sme.semanticId.Count < 1)
            {
                // generate a new one for SME + CD
                // this modifies the SME!
                var id = new AdminShell.Identification(
                    AdminShell.Identification.IRI,
                    AdminShellUtil.GenerateIdAccordingTemplate(_options.TemplateIdConceptDescription));

                context.Sme.semanticId = new AdminShell.SemanticId(
                    new AdminShell.Key(AdminShell.Key.ConceptDescription, true, id.idType, id.id));
            }

            // create, add
            var cd = new AdminShell.ConceptDescription(context?.CD);

            env.ConceptDescriptions.Add(cd);
            var res = new ContextResult()
            {
                Elem = cd
            };

            // link CD to SME
            var sid = context.Sme.semanticId.GetAsExactlyOneKey();

            if (sid == null)
            {
                // should not happen, see above
                return(null);
            }
            cd.identification = new AdminShell.Identification(sid.idType, sid.value);

            // some further attributes
            if (!cd.idShort.HasContent())
            {
                cd.idShort = context.Sme.idShort;
            }

            // ok
            return(res);
        }
        protected ContextResult CreateBodySme(
            ImportCellMatchContextBase context,
            ContextResult refTop)
        {
            // access
            if (context?.Sme == null || refTop?.Wrappers == null)
            {
                return(null);
            }

            // make sure, there is an 'ordniary' SME to create
            var fen = FilteredElementName.Parse(context.SmeElemName);

            if (fen == null)
            {
                return(null);
            }
            if (fen.NameEnum == AdminShellV20.SubmodelElementWrapper.AdequateElementEnum.Unknown)
            {
                return(null);
            }

            // create, add
            var sme = AdminShell.SubmodelElementWrapper.CreateAdequateType(fen.NameEnum, context.Sme);

            refTop.Wrappers.Add(sme);
            sme.parent = refTop.Elem; // unfortunately required, ass Wrapper.Add() cannot set parent
            var res = new ContextResult()
            {
                Elem = sme
            };

            // allow a selection a values
            if (sme is AdminShell.Property prop)
            {
                prop.value = context.SmeValue;

                // demux
                prop.valueType = fen.ValueType;
                if (!fen.ValueType.HasContent() && context.SmeValueType.HasContent())
                {
                    prop.valueType = context.SmeValueType;
                }
            }

            if (sme is AdminShell.MultiLanguageProperty mlp)
            {
                mlp.value = new AdminShell.LangStringSet(AdminShell.LangStr.LANG_DEFAULT, context.SmeValue);
            }

            if (sme is AdminShell.File file)
            {
                file.value = context.SmeValue;
            }

            if (sme is AdminShell.SubmodelElementCollection smc)
            {
                smc.value    = new AdminShell.SubmodelElementWrapperCollection();
                res.Wrappers = smc.value;
            }

            // ok
            return(res);
        }
        protected ContextResult CreateTopReferable(
            ImportCellMatchContextBase context,
            bool actInHierarchy = false)
        {
            // access
            if (context?.Parent == null || _sm == null)
            {
                return(null);
            }

            // what element to create? makes this sense?
            var fen = FilteredElementName.Parse(context.ParentElemName);

            if (fen == null)
            {
                return(null);
            }
            if (fen.Name != AdminShell.Key.Submodel &&
                fen.NameEnum != AdminShell.SubmodelElementWrapper.AdequateElementEnum.Unknown &&
                fen.NameEnum != AdminShell.SubmodelElementWrapper.AdequateElementEnum.SubmodelElementCollection)
            {
                return(null);
            }

            // special case: directly into the (existing) Submodel
            ContextResult res = null;

            if (fen.Name == AdminShell.Key.Submodel)
            {
                // prepare the result (already)
                res = new ContextResult()
                {
                    Elem     = _sm,
                    Wrappers = _sm.submodelElements
                };

                // kind of manually take over data
                // this changes the actual data of the Submodel the plugin is associated with!
                AasConvertHelper.TakeOverSmeToSm(context.Parent, _sm);

                // ok
                return(res);
            }

            // ok, if not, then ordinary case: create a SME and add it (somewhere) to the SM
            // this ALREADY should take over the most of the data
            // Note: value data is not required, as fixed to SMC!
            var sme = AdminShell.SubmodelElementWrapper.CreateAdequateType(fen.NameEnum, context.Parent);

            if (!(sme is AdminShell.SubmodelElementCollection smesmc))
            {
                return(null);
            }

            smesmc.value = new AdminShell.SubmodelElementWrapperCollection();

            res = new ContextResult()
            {
                Elem     = sme,
                Wrappers = smesmc.value
            };

            // try to act within the hierarchy
            // does only search SME but no SM, however, this is not a flaw, as adding to SM is the default
            if (actInHierarchy && context.ParentParentName.HasContent() && context.Parent.idShort.HasContent())
            {
                foreach (var rootsmc in _sm.submodelElements.FindDeep <AdminShell.SubmodelElementCollection>((testsmc) =>
                {
                    // first condition is, that the parents match!
                    if (!testsmc.idShort.HasContent() || testsmc.parent == null)
                    {
                        return(false);
                    }

                    // try testing of allowed parent names
                    if (!(testsmc.parent is AdminShell.Referable testsmcpar))
                    {
                        return(false);
                    }
                    var test1 = context.ParentParentName.ToLower().Contains(testsmcpar.idShort.ToLower().Trim());
                    var test2 = false;
                    if (_idShortToParentName.ContainsKey(testsmcpar.idShort))
                    {
                        foreach (var pn in _idShortToParentName[testsmcpar.idShort])
                        {
                            test2 = test2 || context.ParentParentName.ToLower().Contains(pn.ToLower().Trim());
                        }
                    }

                    if (!(test1 || test2))
                    {
                        return(false);
                    }

                    // next is, that some part of of given idShort match the idShort of children
                    // of investigated SMC
                    var parts = context.Parent.idShort.Split(new[] { ',', ';', '|' },
                                                             StringSplitOptions.RemoveEmptyEntries);
                    foreach (var part in parts)
                    {
                        if (part?.Trim().ToLower() == testsmc.idShort.Trim().ToLower())
                        {
                            return(true);
                        }
                    }

                    // or, maybe more meaningful, if the semantic ids are the same?
                    if (context.Parent.semanticId?.IsEmpty == false &&
                        testsmc.semanticId?.IsEmpty == false &&
                        testsmc.semanticId.Matches(context.Parent.semanticId, AdminShell.Key.MatchMode.Relaxed))
                    {
                        return(true);
                    }

                    // not found
                    return(false);
                }))
                {
                    // rootsmc contains a valid SMC to the above criteria
                    // NOTHING needs to be added; found SMC needs to be given back
                    res.Elem     = rootsmc;
                    res.Wrappers = rootsmc.value;

                    // this seems to be a valid ParentName, which is now "renamed" by the idShort
                    // of the SMC
                    _idShortToParentName.Add(rootsmc.idShort, context.Parent.idShort);

                    // need to adopt the rootsmc further by parent information??
                    ;

                    // ok
                    return(res);
                }
            }

            // simply add new SMC directly to SM
            _sm.Add(sme);
            return(res);
        }