BomItem.cs

*BomItem.cs*

using Bartech.SGCore.Base;
using Bartech.SGCore.Base.Web;
using Bartech.SGCore.Helpers;
using Bartech.SGCore.Local.DataObjects;
using Bartech.SGCore.Local.Services;
using Bartech.SGCore.Logic.Shared.Messages;
using Bartech.SGCore.Model;
using Bartech.SGCore.Model.API.Request;
using Bartech.SGCore.Model.API.Request.Common;
using Bartech.SGCore.Model.API.Response;
using Bartech.SGCore.Model.ContextData;
using Bartech.SGCore.Model.Messages;
using Bartech.xTrace.TSE.Services;
using DevExpress.Xpo;
using DevExpress.Xpo.Helpers;
using Microsoft.VisualBasic;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.UI;
using xTrace03_SG_Data;

namespace Bartech.SGCore.Local
{
    [XModule("BOM_Item", "Modul pro načítání komponent", ModuleGroupType.Part, applicationType: xTraceApplicationType.BomItem)]
    public class SGBomItem : SGModuleLocal
    {
        #region konstrukor
        public SGBomItem(SGSession session)
            : base(session)
        {
            m_dxSession = Session.Resolve<SGDxSessionLocker>();
            m_inputBatchService = Session.Resolve<InputBatchService>();
            m_componentCheckSvc = session.Resolve<ComponentCheckService>();
            //m_dataForwardSvc = Session.Resolve<TSEDataForwardService>();
            m_prodSvc = Session.Resolve<ProductService>();
            Session.GlobalContext.SetBOMComponents(new FullyObservableCollection<BusItem>());

            m_globalContextComponents = new ObservableCollection<BusItem>();
            m_wholeContextComponents = new ObservableCollection<BusItem>();
            AllowedInDevs = new SGDeviceType[] { SGDeviceType.Scanner, SGDeviceType.API };
            katalog = new DOKatalogParams(this, "Material");
        }
        #endregion

        #region privatni promenne
        private SGDxSessionLocker m_dxSession;
        private ProductService m_prodSvc;
        private InputBatchService m_inputBatchService;
        private ComponentCheckService m_componentCheckSvc;

        private string m_alarmCDOnNoTechnlogyData;
        private bool m_useBlocker;
        private int m_ioBlockDefinition = 1;
        private long m_lastJobID;
        private BusOperation m_lastOperation;
        private bool m_sendAlarmCDOnNoTechnlogyData;
        private bool m_addImmediatelyToBatchOp;
        TSEDataForwardService m_dataForwardSvc;
        ObservableCollection<BusItem> m_globalContextComponents;
        ObservableCollection<BusItem> m_wholeContextComponents;
        private bool m_checkSlot;
        private string m_slotRegEx;
        private bool m_WaitForProgram;
        private bool m_waitingForSlot;
        private BusItem m_CurrentComponent;
        private bool m_prepared;
        private bool m_continuousFilling;
        private LogMessage tmp_message = null;
        private bool m_isPositionNeeded;
        private List<BusItem> m_currentComponentList;
        private List<long> m_positionIDList;
        private bool m_isDockingCartAccepted;
        private DOKatalogParams katalog;
        private bool m_ignorePaste;
        private bool m_loadReferenciesForSlot;
        private bool m_loadOrderRequired;
        private bool m_debugLogActive;
        private bool m_clearLoadedComponentsOnJobChanged;
        private bool m_showBomOnlyForSlots;
        private bool m_sendOnlyOneComponent;        
        #endregion

        public bool CheckSlot { get => m_checkSlot; set => Set(() => CheckSlot, ref m_checkSlot, value); }
        public string SlotRegex { get => m_slotRegEx; set => Set(() => SlotRegex, ref m_slotRegEx, value); }

        #region public properties

        public bool ContinuousFilling { get => m_continuousFilling; private set => m_continuousFilling = value; }
        public bool Prepared { get { return m_prepared; } set { Set(() => Prepared, ref m_prepared, value); } }
        public bool CheckFinished
        {
            get
            {
                if (m_ignorePaste)
                    return Session.GlobalContext.BOMComponents.Where(x => x.IsPaste == false).All(x => x.Matched || x.PositionMatched);
                else
                    return Session.GlobalContext.BOMComponents.All(c => c.Matched || c.PositionMatched);
            }
        }
        public bool ShowBomOnlyForSlots { get => m_showBomOnlyForSlots; }
        #endregion

        #region Private methods
        private void Block()
        {
            if (m_useBlocker) Session.Resolve<IOPortBlockerService>().Block(m_ioBlockDefinition);
        }
        public bool CreateInputBatch(string batchCD, long productID)
        {
            DOInputBatch doInputBatch = new DataObjects.DOInputBatch(this);
            bool rc = doInputBatch.Add(batchCD, string.Empty, string.Empty, 0, DateTime.MinValue, batchCD, productID, DateTime.MinValue);

            return rc;
        }
        #endregion
        #region module overrides
        protected override bool OnSetParameters()
        {
            string s = Session.SysParams.TryGetString(this, "AlarmCDOnNoTechnologyData", "A00203", "Kód alarmu, který se vyvolá pokud nejsou nastaveny technologické časy.");
            Session.Alarm.AlarmExists(s, out m_sendAlarmCDOnNoTechnlogyData);
            m_alarmCDOnNoTechnlogyData = s;
            m_useBlocker = Session.SysParams.GetBoolean(this, "UseBlocker", true, "Určuje, zda má modul má modul nastavovat blokaci pracoviště");
            m_ioBlockDefinition = Session.SysParams.GetInt32(this, "IOBlockDefinition", 1, "Určuje, která definice blokování v modulu IOPortBlockerService se má použít (1=BlockState, 2=BlockState2)");
            ContinuousFilling = Session.SysParams.GetParamValue(this, "ContinuousFilling", false, "Určuje, zda se má čekat na další komponenty i po načtení všech požadovaných komponent");
            var dataPorts = Session.SysParams.TryGetString(this, "ForwardingCOMports", "", "Řetězec definující přeposílání dat mezi COM porty (např: port 1 přeposlat na port 5 a port 2 na port 6: \"1=>5;2=>6\")");
            if (dataPorts != String.Empty)
            {
                m_dataForwardSvc.CreateMappingCOMports(dataPorts);
            }
            m_addImmediatelyToBatchOp = Session.SysParams.GetParamValue(this, "AddImmediatelyToBatchOp", false, "Určuje, zda se má komponenta okamžitě uložit k operaci");
            m_checkSlot = Session.SysParams.GetParamValue(this, "CheckSlot", false, "Určuje, zda se má načítat a ověřovat slot, kam se komponenta do stroje zakládá.");
            m_slotRegEx = Session.SysParams.TryGetString(this, "SlotRegEx", "", "RegEx na slot, který se načte scannerem.");
            m_WaitForProgram = Session.SysParams.GetParamValue(this, "WaitForProgram", false, "Jestli je true, potom modul bude cekat az se v GlobalContext.CurrentMachineProgram nastavi program.");
            m_isPositionNeeded = Session.SysParams.GetParamValue(this, "IsPositionNeeded", false, "Jestli je true, tak je po načtení komponenty potřeba načíst pozici");
            m_isDockingCartAccepted = Session.SysParams.GetBoolean(this, "IsDockingCartAccepted", false, "Jestli je true, tak povoluje načítání vozíků s materiálem");
            m_ignorePaste = Session.SysParams.GetBoolean(this, "IgnorePaste", false, "Je-li true, tak se nenacita material typu pasta v setupu");
            m_loadReferenciesForSlot = Session.SysParams.GetBoolean(this, "LoadReferenciesForSlot", false, "Je-li true, dojde k načtení šarže komponenty pouze pro referenční slot");
            m_loadOrderRequired = Session.SysParams.GetBoolean(this, "OrderRequired", false, "Je-li true, tak se musí načítat součásky v pořádí podle kusovníku");
            m_debugLogActive = Session.SysParams.GetBoolean(this, "DebugLogActive", false, "Zapinani debugovych hlaseni");
            m_clearLoadedComponentsOnJobChanged = Session.SysParams.GetBoolean(this, "ClearLoadedComponentsOnJobChanged", false, "Je-li true, tak při změně jobu dojde k automatickému odnačtení a smazání doposud načteného materiálu");
            m_showBomOnlyForSlots = Session.SysParams.GetBoolean(this, "ShowBomOnlyForSlots", false, "Je-li true, tak se v záložce Kusovník zobrazí požadovaný materiál pouze pro požadované sloty nikoli celý jak byl původně načten");
            m_sendOnlyOneComponent = Session.SysParams.GetBoolean(this, "SendOnlyOneComponents", true, "Je-li true, tak se v záložce Kusovník zobrazí požadovaný materiál pouze pro požadované sloty nikoli celý jak byl původně načten");            
            return base.OnSetParameters();
        }

        public override void StartLevel(SGTreeModuleData mdata)
        {
            if (Session.Job.GetEffectiveDOJob().JobID != m_lastJobID || Session.CycleContext.OperationOverride != m_lastOperation)
            {
                LoadComponents(true);
                Block();
                return;
            }
            if (Prepared) return;
            base.StartLevel(mdata);
        }

        //!!TODO!! - prepsat celu tuto silenost ala BomItemReplacer
        public override SGLMState HandlePortData(SGTreeModuleData mdata, SGReceivedData data)
        {
            SGLMState s = SGLMState.NotHandled;
            if (mdata.LevelState == SGLevelState.Echo)
            {
                s = SGLMState.Handled;

                if (m_WaitForProgram && !Session.GlobalContext.CurrentMachineProgram.IsSet)
                {
                    Message = Log(LogMsg.IAC_GET_PROGRAMNO_Waiting);
                    return s;
                }
                if (!m_waitingForSlot)
                {
                    m_CurrentComponent = new BusItem();
                    if (m_isDockingCartAccepted)
                        Message = Log(LogMsg.SMT_WaitingForComponentOrDockingCart);
                    else
                        Message = Log(LogMsg.SMT_WaitingForComponent);
                }
                else
                    Message = Log(LogMsg.BOM_ITEM_WaitingForSlotOrComponent, m_CurrentComponent.ComponentCD);
            }
            else
            {
                s = SGLMState.NotHandled;
                if (data.DataType == DataType.InputBatch)
                {
                    s = SGLMState.Handled | SGLMState.ResetIndex;

                    // tady se musi z barcode vyparsovat 3 group (P)MAT, (L)BATCH, (S)BATCHSN
                    string regexText = Session.Data.GetCodeDef(data).RegexText;
                    var regx = new Regex(regexText).Match(data.Text);
                    if (regx.Success)
                    {
                        s = SGLMState.Handled;

                        // NVCZ kod se musi optimalizovat do lepsi podoby aby to bylo unoverzalni
                        string compCD = regx.Groups["MATCD"].Value.TrimEnd();
                        string batch = regx.Groups["BATCHCD"].Value.Trim();
                        string sn = regx.Groups["BATCHSN"].Value.Trim();

                        bool pbSnOnly = string.IsNullOrEmpty(batch) && !string.IsNullOrEmpty(sn);
                        bool pbBatchAndSn = !string.IsNullOrEmpty(batch) && !string.IsNullOrEmpty(sn);
                        bool pbCompAndBatch = !string.IsNullOrEmpty(compCD) && !string.IsNullOrEmpty(batch);

                        BusInputBatchSerial bibSn = null;
                        BusInputBatch bib = null;

                        //pokud se musi dodrzet poradi nacitani zkontroluju, ze nacitam SX prvniho nematchnuteho zaznamu
                        if (m_loadOrderRequired && compCD != Session.GlobalContext.BOMComponents.Where(x => x.Matched == false && x.IsSlotNeeded == true).FirstOrDefault().ComponentCD)
                        {
                            Message = Log(LogMsg.BOM_ITEM_IncorrectMaterial, compCD);
                            return SGLMState.Handled | SGLMState.Fail;
                        }
                        // tady by se melo osetrit co nacitam za kod. pokud sn tak najdu prvni inputbatchsn a inputbatch abych vedel soucastku, pokud kod soucastku a sarze tak musim hledat prvni soucastku v kusovniku a pak dotahovat sarzi

                        // pokud by me dosla v kodu sarze a sn nebo sn sarze mel bych prvni hledat sarzi a sn a potom se divat na komponentu

                        // najdi soucastku v ciselniku
                        m_currentComponentList = GetAllComponentsForCode(compCD);
                        m_CurrentComponent = m_currentComponentList.ElementAtOrDefault(0);
                        BusItem componentClone;

                        if (SetError(m_CurrentComponent != null, LogMsg.SMT_ComponentUnwanted, sn, batch, compCD))
                        {
                            //
                            if (m_loadReferenciesForSlot)
                            {
                                m_positionIDList = GetAllPositionsForCode(compCD, m_CurrentComponent.MachineID, m_CurrentComponent.MachineSideCD, m_CurrentComponent.RequestedSlot);
                            }
                            else
                                m_positionIDList = GetAllPositionsForCode(compCD);
                            bool addToCollection = false;
                            s = CheckComponent(m_CurrentComponent, out addToCollection);
                            if ((s & SGLMState.OK) == SGLMState.OK)
                            {
                                // najdi prvni komponentu co nema match
                                m_CurrentComponent = GetFirstUnMatchedComponentFromBom(compCD);
                                // mam neco?
                                if (m_CurrentComponent == null)
                                {
                                    Message = Log(LogMsg.SMT_ComponentAlreadyInList, compCD);
                                    return s;
                                }
                                else
                                {
                                    componentClone = m_CurrentComponent.Clone();
                                }

                                // najdi inputbatch
                                bib = m_inputBatchService.GetInputBatch(m_dxSession, batch, componentClone.ComponentID, true);

                                // pokud neexistuje a mam zalozit tak to udelej
                                if (bib == null && m_CurrentComponent.BatchMustExist)
                                {
                                    Message = Log(LogMsg.DRYER_BatchNotFound, batch);
                                    return SGLMState.Handled | SGLMState.Fail;
                                }
                                if (bib == null && !m_CurrentComponent.BatchMustExist && CreateInputBatch(batch, componentClone.ComponentID))
                                    bib = m_inputBatchService.GetInputBatch(m_dxSession, batch, componentClone.ComponentID, true);

                                if (bib.IsBlocked)
                                {
                                    Message = Log(LogMsg.INPUTBATCH_IsBlocked, bib.BatchCD, bib.ComponentCD, bib.BlockedMessage);
                                    m_CurrentComponent = null;
                                    bib = null;
                                    return SGLMState.Handled | SGLMState.Fail;
                                }

                                var inputBatchSN = new BusInputBatchSerial(m_inputBatchService);
                                if (SetError(bib != null, LogMsg.BATCH_BatchSnNotFound, data.Text, batch, sn) && m_componentCheckSvc.CanUseComponent(this, m_dxSession, inputBatchSN, bib, SetError, Log, ref tmp_message))
                                {
                                    // nastav sarzi do komponenty
                                    componentClone.SetInputBatch(batch, sn);
                                    componentClone.SetInputBatchID(bib.OID);

                                    //pokud je vypnute nacitani slotu nebo u dane komponenty neni pozadovany konkretni slot
                                    if (!m_checkSlot || !m_CurrentComponent.IsSlotNeeded)
                                    {
                                        componentClone.SetAsMatched();
                                    }
                                    // pokud se ma nacitat slot (feeder) pak jestli ho mas nacteny dej do seznamu a nastav IsMatch
                                    else if (componentClone.SlotMatched)
                                    {
                                        componentClone.SetAsMatched();
                                    }
                                    else
                                        m_waitingForSlot = true;
                                    m_CurrentComponent = componentClone;
                                }
                                else if (tmp_message != null)
                                {
                                    s = SGLMState.Handled | SGLMState.Fail;
                                    Message = tmp_message;
                                }
                                if (componentClone.Matched && addToCollection)
                                {
                                    foreach (long position in m_positionIDList)
                                    {
                                        BusItem component;
                                        if (!m_CurrentComponent.IsSlotNeeded)
                                            component = Session.GlobalContext.BOMComponents.Where(x => x.PositionID == position && x.ComponentCD == m_CurrentComponent.ComponentCD).FirstOrDefault();
                                        else
                                            component = Session.GlobalContext.BOMComponents.Where(x => x.PositionID == position && x.ComponentCD == m_CurrentComponent.ComponentCD && x.FullRequestedSlot.Equals(m_CurrentComponent.FullRequestedSlot)).FirstOrDefault();
                                        component.SetInputBatch(batch, sn);
                                        component.SetInputBatchID(bib.OID);
                                        component.SetAsMatched();
                                        SetGlobalCollectionItem(component);
                                        Session.CycleContext.Components.Add(component);
                                    }
                                    Message = Log(LogMsg.BOM_ITEM_ComponentLoaded, m_CurrentComponent.ComponentName);
                                    Session.Messenger.Send<GlobalCollectionBusItemCollectionChanged>(new GlobalCollectionBusItemCollectionChanged(Session.GlobalContext.BOMComponents));

                                    m_CurrentComponent = null;
                                }
                            }
                        }
                    }
                    // jestli cekam na slot a mam komponentu
                }
                else if (m_waitingForSlot && m_CurrentComponent != null && data.DeviceType == SGDeviceType.Scanner)
                {
                    // slot bude v regexu
                    var slotRegx = new Regex(m_slotRegEx).Match(data.Text);
                    Regex slotRegex = new Regex(m_slotRegEx);
                    Match m = slotRegex.Match(data.Text);
                    if (m.Success)
                    {
                        s = SGLMState.Handled | SGLMState.ResetIndex;
                        string machineid = slotRegx.Groups["MachineNUM"].Value.TrimEnd();
                        string side = slotRegx.Groups["Side"].Value.TrimEnd();
                        string slot = slotRegx.Groups["PosNUM"].Value.TrimEnd();

                        // najdi komponentu na machineid, side a slotu
                        var c = GetComponentFromBom(m_CurrentComponent.ComponentCD, machineid, side, slot);

                        if (m_loadReferenciesForSlot)
                        {
                            m_positionIDList = GetAllPositionsForCode(m_CurrentComponent.ComponentCD, m_CurrentComponent.MachineID, m_CurrentComponent.MachineSideCD, m_CurrentComponent.RequestedSlot);
                        }
                        else
                            m_positionIDList = GetAllPositionsForCode(m_CurrentComponent.ComponentCD);

                        if (SetError(c != null, LogMsg.BOM_ITEM_ComponentForIncorrectSlot, m_CurrentComponent.ComponentCD, machineid, side, slot))
                        {
                            var batch = m_CurrentComponent.InputBatchCD;
                            var sn = m_CurrentComponent.InputBatchSerialCD;
                            var bibid = m_CurrentComponent.InputBatchID;
                            m_CurrentComponent = c;
                            m_CurrentComponent.SetInputBatch(batch, sn);
                            m_CurrentComponent.SetUsedSlot(slot);

                            if (m_CurrentComponent.SlotMatched)
                            {
                                foreach (var position in m_positionIDList)
                                {
                                    BusItem component;
                                    if (!m_CurrentComponent.IsSlotNeeded)
                                        component = Session.GlobalContext.BOMComponents.Where(x => x.PositionID == position && x.ComponentCD == m_CurrentComponent.ComponentCD).FirstOrDefault();
                                    else
                                        component = Session.GlobalContext.BOMComponents.Where(x => x.PositionID == position && x.ComponentCD == m_CurrentComponent.ComponentCD && x.FullRequestedSlot.Equals(m_CurrentComponent.FullRequestedSlot)).FirstOrDefault();
                                    component.SetInputBatch(batch, sn);
                                    component.SetInputBatchID(m_CurrentComponent.InputBatchID);
                                    component.SetAsMatched();
                                    component.SetUsedSlot(slot);
                                    SetGlobalCollectionItem(component);
                                    Session.CycleContext.Components.Add(component);
                                }
                                Message = Log(LogMsg.BOM_ITEM_SlotChecked, m_CurrentComponent.FullRequestedSlot);
                                Session.Messenger.Send<GlobalCollectionBusItemCollectionChanged>(new GlobalCollectionBusItemCollectionChanged(Session.GlobalContext.BOMComponents));
                                m_CurrentComponent = null;
                                m_waitingForSlot = false;
                                s |= SGLMState.OK;
                            }
                        }
                        s |= SGLMState.Fail;
                    }
                }
                //zpracovani dat, ktere prisly z HTTP-API
                else if (data.DeviceType == SGDeviceType.API)
                {
                    IEnumerable<BusItem> responseBusItemEnumerable;
                    if (m_sendOnlyOneComponent)
                    {
                        responseBusItemEnumerable = Session.GlobalContext.BOMComponents.Where(x => x.Matched == false).Take(1);
                    }
                    else
                    {
                        responseBusItemEnumerable = Session.GlobalContext.BOMComponents;
                    }
                    if (data.Data is ApiRequestDataComponents)
                    {
                        ApiRequestDataComponents httpApiDataComponentsDataRequest = data.Data as ApiRequestDataComponents;
                        if (httpApiDataComponentsDataRequest == null)
                            return SGLMState.NotHandled;

                        s = HandleComponentData(httpApiDataComponentsDataRequest.ComponentCD);
                        if ((s & SGLMState.OK) == SGLMState.OK)
                        {
                            Session.Messenger.Send(new HttpApiResponseMessage(new ApiResponseDataComponents()
                            {
                                Result = "",
                                Text = "",
                                GlobalContextComponents = responseBusItemEnumerable,
                                WaitingForSlot = m_CurrentComponent.IsSlotNeeded
                            }));
                        }
                        else
                        {
                            Session.Messenger.Send(new HttpApiResponseMessage(new ApiResponseDataComponents()
                            {
                                Result = "error",
                                Text = Message.TextFormatted,
                                GlobalContextComponents = responseBusItemEnumerable,
                            }));
                        }
                    }
                    else if (data.Data is ApiRequestDataComponentSlot)
                    {
                        ApiRequestDataComponentSlot httpApiRequestDataComponentSlot = data.Data as ApiRequestDataComponentSlot;
                        if (httpApiRequestDataComponentSlot == null)
                            return SGLMState.NotHandled;
                        if (!string.IsNullOrEmpty(httpApiRequestDataComponentSlot.Slot))
                            s = HandlePositionData(httpApiRequestDataComponentSlot.Slot);
                        else
                            s = HandlePositionData(httpApiRequestDataComponentSlot.MachineNumber, httpApiRequestDataComponentSlot.MachineSide, httpApiRequestDataComponentSlot.Position);
                        if ((s & SGLMState.OK) == SGLMState.OK)
                        {
                            Session.Messenger.Send(new HttpApiResponseMessage(new ApiResponseDataComponents()
                            {
                                Result = "",
                                Text = "",
                                GlobalContextComponents = responseBusItemEnumerable
                            }));
                        }
                        else
                        {
                            Session.Messenger.Send(new HttpApiResponseMessage(new ApiResponseDataComponents()
                            {
                                Result = "error",
                                Text = Message == null ? "Neznámá chyba" : Message.TextFormatted,
                                GlobalContextComponents = responseBusItemEnumerable
                            }));
                        }
                    }
                    else if (mdata.GotControl && data.Data is ApiRequestDataCheckActualStep)
                    {
                        SendActualStep();
                        return SGLMState.Handled;
                    }
                }
                else if (m_isDockingCartAccepted && data.DataType == DataType.Carrier)
                {
                    s = HandleDockingCartData(data.Text);
                }
                else if (!ContinuousFilling)
                {
                    // ukonceni pripravi materialu
                    if (data.Text == "C0304")
                    {
                        if (Prepared) return SGLMState.Handled | SGLMState.OK;

                        Prepared = true;
                        foreach (var c in Session.GlobalContext.BOMComponents) { c.SetAsMatched(); }
                        // odeslat zpravu do eteru
                        Session.Messenger.Send<InputBatchGroupChangedMessage>(new InputBatchGroupChangedMessage());
                        Message = Log(LogMsg.SMT_ComponentPreparationFinished);
                        return SGLMState.Handled | SGLMState.UpLevel;
                    }
                }

            }
            LogResult();
            return s;
        }

        public override void Clear()
        {
            Session.GlobalContext.BOMComponents.Clear();
            Session.CycleContext.Components.Clear();
            Session.Messenger.Send<GlobalCollectionBusItemCollectionChanged>(new GlobalCollectionBusItemCollectionChanged(Session.GlobalContext.BOMComponents));
            m_lastJobID = 0;
            if (m_lastOperation != null)
            {
                m_lastOperation.Clear();
            }
            Prepared = false;
            base.Clear();
        }
        public override SGLMState ModuleChecker(SGTreeModuleData mdata)
        {
            SGLMState s;
            if (ContinuousFilling)
            {
                s = base.ModuleChecker(mdata);
            }
            else
            {
                Prepared = CheckFinished;
                if (Prepared)
                {   // odeslat zpravu do eteru
                    Session.Messenger.Send<InputBatchGroupChangedMessage>(new InputBatchGroupChangedMessage());
                    return mdata.IsMaster ? SGLMState.Handled | SGLMState.UpLevel : SGLMState.NotHandled;
                }
                s = base.ModuleChecker(mdata);
            }
            return s;
        }
        #endregion

        #region pomocne funkce
        private SGLMState HandleDockingCartData(string dockingCartCD)
        {
            SGLMState s = SGLMState.Handled;
            if (SetError(Session.BomItemPreparer.DoDockingCart.CheckDockingCartExist(dockingCartCD), LogMsg.DockingCart_NotFound, dockingCartCD))
            {
                if (SetError(Session.BomItemPreparer.DoDockingCart.GetSlotsByInputBatchesFromDockingCart(dockingCartCD), LogMsg.DockingCart_IsEmpty, dockingCartCD))
                {
                    if (Session.BomItemPreparer.DoDockingCart.IsForActualJobAndPosIndex)
                    {
                        //pokud se ma kontrolovat slot, tak se krome poslani productCD a InputBatch posle i ulozeny slot
                        if (m_checkSlot)
                        {
                            foreach (var item in Session.BomItemPreparer.DoDockingCart.SlotsByInputBatches)
                            {
                                Session.SetNextData(Session.Data.CreateReceivedData(SGDeviceType.Scanner, item.Key.ComponentCD + " " + item.Key.BatchCD, false)); //automaticke poslani productCD a inputbatche
                                Session.SetNextData(Session.Data.CreateReceivedData(SGDeviceType.Scanner, "**" + item.Value, false)); //automaticke poslani ulozene slotu u materialu ve voziku
                            }
                        }
                        //pokud se nema kontrolovat slot, tak se pouze podhodi productCD a inputbatch z voziku
                        else
                        {
                            foreach (var item in Session.BomItemPreparer.DoDockingCart.SlotsByInputBatches)
                            {
                                //z nacteneho materialu ve voziku se vezme ProductCD prida mezera a BatchCD a posle se to jako TerminalPort 1
                                string ibToBeSend = item.Key.ComponentCD + " " + item.Key.BatchCD;
                                Session.SetNextData(Session.Data.CreateReceivedData(SGDeviceType.Scanner, ibToBeSend, false));
                            }
                        }
                        s |= SGLMState.OK;
                    }
                    else
                    {
                        Message = Log(LogMsg.DockingCart_ForDifferentJobOrOperation,
                            Session.BomItemPreparer.DoDockingCart.DockingCartCD,
                            Session.Job.DoJob.JobID, Session.CycleContext.OperationOverride.RoutingPosIndex,
                            Session.BomItemPreparer.DoDockingCart.JobID, Session.BomItemPreparer.DoDockingCart.RoutingPosIndex);
                        s |= SGLMState.Fail;
                    }
                }
            }
            else
            {
                s |= SGLMState.Fail;
            }
            return s;
        }
        public virtual void LoadComponents(bool clear)
        {
            if (clear)
            {
                m_globalContextComponents.Clear();
                m_wholeContextComponents.Clear();
            }
            LoadGlobalContextComponents();

            if (m_debugLogActive)
            {
                foreach (var item in m_globalContextComponents)
                {
                    Message = Log(LogMsg.CUSTOM_INFO_MSG, $"Tempova kolekce Kod materialu {item.ComponentCD}, reference {item.PositionCD}, mnozstvi {item.Quantity}");
                }

                foreach (var item in Session.GlobalContext.BOMComponents)
                {
                    Message = Log(LogMsg.CUSTOM_INFO_MSG, $"GlobalContext kolekce Kod materialu {item.ComponentCD}, reference {item.PositionCD}, mnozstvi {item.Quantity}");
                }
                foreach (var item in Session.CycleContext.Components)
                {
                    Message = Log(LogMsg.CUSTOM_INFO_MSG, $"CycleContext kolekce Kod materialu {item.ComponentCD}, sarze nacteneho materialu {item.InputBatchCD} reference {item.PositionCD}, mnozstvi {item.Quantity}");
                }
            }
            FullyObservableCollection<BusItem> temp = new FullyObservableCollection<BusItem>();
            //pokud je zapnuto automaticke odnacitani materialu pri zmene jobu
            if (m_clearLoadedComponentsOnJobChanged)
            {
                ClearLoadedComponents();
                foreach (var component in m_globalContextComponents)
                {
                    temp.Add(component);
                }
                Session.GlobalContext.SetBOMComponents(temp);
            }
            else
            {
                if (CompareComponents(Session.GlobalContext.BOMComponents, m_globalContextComponents))
                {
                    ClearLoadedComponents();
                    foreach (var component in m_globalContextComponents)
                    {
                        temp.Add(component);
                    }
                    Session.GlobalContext.SetBOMComponents(temp);
                }
            }
            Session.Messenger.Send<GlobalCollectionBusItemCollectionChanged>(new GlobalCollectionBusItemCollectionChanged(Session.GlobalContext.BOMComponents));
            m_lastJobID = Session.Job.GetEffectiveDOJob().JobID;
            m_lastOperation = Session.CycleContext.OperationOverride;

            //debugovaci logovani kusovniku
            if (m_debugLogActive)
            {
                foreach (var item in Session.GlobalContext.BOMComponents)
                {
                    Message = Log(LogMsg.CUSTOM_INFO_MSG, $"Kod materialu {item.ComponentCD}, reference {item.PositionCD}, mnozstvi {item.Quantity}");
                }
            }
        }

        public void ClearLoadedComponents()
        {
            Session.GlobalContext.BOMComponents.Clear();
            Session.CycleContext.Components.Clear();
            Prepared = false;
            if (m_debugLogActive)
                Message = Log(LogMsg.CUSTOM_INFO_MSG, "Čistím kolekce v paměti");
        }
        /// <summary>
        /// Nacte komponentu z kusovniku (original kusovnik co je na operaci)
        /// </summary>
        /// <param name="componentCD"></param>
        /// <returns></returns>
        public virtual BusItem GetComponentFromBom(string componentCD)
        {
            return Session.GlobalContext.BOMComponents.FirstOrDefault(x => x.ComponentCD == componentCD);
        }
        public virtual BusItem GetComponentFromBom(string componentCD, string machineID, string machineSideCD, string slot)
        {
            return Session.GlobalContext.BOMComponents.FirstOrDefault(x => x.ComponentCD == componentCD && x.MachineID == machineID && x.MachineSideCD == machineSideCD && x.RequestedSlot == slot);
        }
        public virtual BusItem GetComponentFromCycleContext(string componentCD, string machineID, string machineSideCD, string slot)
        {
            return Session.CycleContext.Components.FirstOrDefault(x => x.ComponentCD == componentCD && x.MachineID == machineID && x.MachineSideCD == machineSideCD && x.RequestedSlot == slot);
        }
        public virtual BusItem GetFirstUnMatchedComponentFromBom(string componentCD)
        {
            return Session.GlobalContext.BOMComponents.FirstOrDefault(x => x.ComponentCD == componentCD && !x.Matched);
        }
        public virtual List<BusItem> GetAllComponentsForCode(string componentCD)
        {
            return Session.GlobalContext.BOMComponents.Where(x => x.ComponentCD == componentCD && x.Matched == false).ToList();
        }
        public virtual List<long> GetAllPositionsForCode(string componentCD)
        {
            return Session.GlobalContext.BOMComponents.Where(x => x.ComponentCD == componentCD).Select(x => x.PositionID).ToList();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="componentCD"></param>
        /// <param name="machineID"></param>
        /// <param name="side"></param>
        /// <param name="slot"></param>
        /// <returns></returns>
        public virtual List<long> GetAllPositionsForCode(string componentCD, string machineID, string side, string slot)
        {
            return Session.GlobalContext.BOMComponents.Where(x => x.ComponentCD == componentCD && x.MachineID == machineID && x.MachineSideCD == side && x.RequestedSlot == slot).Select(x => x.PositionID).ToList();
        }
        /// <summary>
        /// Porovnej dva seznamy komponent jestli jsou stejne
        /// </summary>
        /// <param name="sourceCollection"></param>
        /// <param name="targetCollection"></param>
        /// <returns>vrati true, pokud NEjsou kolekce stejne </returns>
        public bool CompareComponents(ObservableCollection<BusItem> sourceCollection, ObservableCollection<BusItem> targetCollection, bool logit = false)
        {
            bool areCollectionDifferent = false;
            if (targetCollection.Count() != sourceCollection.Count())
                return areCollectionDifferent = true;

            for (int i = 0; i < targetCollection.Count(); i++)
            {
                for (int j = 0; j < sourceCollection.Count(); j++)
                {
                    if (sourceCollection[j].ComponentCD == targetCollection[i].ComponentCD && sourceCollection[j].InputBatchCD == targetCollection[i].InputBatchCD)
                    {
                        sourceCollection[j].CompareMatched = true;
                        targetCollection[j].CompareMatched = true;
                    }
                }
            }
            //kolekce obsahuji jiny pocet zaznamu nebo v kolekcich existuje takovy nastroj, ktery neni v obou kolekcich
            if ((sourceCollection.Any(x => x.CompareMatched == false) || targetCollection.Any(x => x.CompareMatched == false)))
                areCollectionDifferent = true;
            if (areCollectionDifferent && logit)
            {
                //BOM_ITEM_SAVE
                //sourceCollection je posledni zalozena kolekce BusItem v nejake InputBatchGroup
                Message = Log(LogMsg.CUSTOM_INFO_MSG, "Seznam komponent a jejich sarzi z puvodni kolekce, ktere nejsou v nove kolekci");
                foreach (var item in sourceCollection.Where(x => x.CompareMatched == false))
                    Message = Log(LogMsg.CUSTOM_INFO_MSG, $"Kod materialu: {item.ComponentCD} {item.InputBatchCD}");
                //targetCollection je aktualni kolekce BusItem, u ktere musim zjistit, jestli neni odlisna od posledni ulozene kolekce
                Message = Log(LogMsg.CUSTOM_INFO_MSG, "Seznam komponent a jejich sarzi z nove kolekce, ktere nejsou v puvodni kolekci");
                foreach (var item in targetCollection.Where(x => x.CompareMatched == false))
                    Message = Log(LogMsg.CUSTOM_INFO_MSG, $"Kod materialu: {item.ComponentCD} {item.InputBatchCD}");
            }
            return areCollectionDifferent;
        }

        public virtual bool IgnoreComponent(BusItem c)
        {
            if (c.ComponentID == 0) return true;
            DOKatalogParams k = new DOKatalogParams(this, "Material");
            k.Load(c.ComponentID);
            return k.GetValue<bool>("IsPaste", false, true);
        }

        public bool IsComponentFromCurrentOp(BusItem component)
        {
            //TODO - Zeptat se Toma na porovnavani podle OID komponent
            //porovnavat OID nebo ComponentID 
            return Session.GlobalContext.BOMComponents.Any(x => x.ComponentID == component.ComponentID);
        }

        public virtual SGLMState CheckComponent(BusItem component, ObservableCollection<BusItem> componentCollection)
        {
            bool addComponentToCollection = false;
            return CheckComponent(component, componentCollection, out addComponentToCollection);
        }

        public virtual SGLMState CheckComponent(BusItem component, out bool addToCollection)
        {
            return CheckComponent(component, Session.CycleContext.Components, out addToCollection);
        }

        public virtual SGLMState CheckComponent(BusItem component, ObservableCollection<BusItem> componentCollection, out bool addComponentToCollection)
        {
            addComponentToCollection = false;
            SGLMState s = SGLMState.NotHandled;
            if (!IsComponentFromCurrentOp(component))
            {
                //preposlani na nejaky COM port
                s = SGLMState.Handled | SGLMState.OK;
            }
            else if (IsComponentFromCurrentOp(component))
            {
                addComponentToCollection = true;
                s = SGLMState.Handled | SGLMState.OK;
            }
            return s;
        }

        public virtual bool Recheck() { return true; }

        private SGLMState HandleComponentData(string data)
        {
            SGLMState s = SGLMState.Handled | SGLMState.ResetIndex;

            // tady se musi z barcode vyparsovat 3 group (P)MAT, (L)BATCH, (S)BATCHSN
            SGCodeDef codeDef = Session.Data.GetCodeDef(data);
            if (codeDef == null)
            {
                Message = Log(LogMsg.LOCALMANAGER_UnhandledData, data);
                return s | SGLMState.Fail;
            }
            string regexText = codeDef.RegexText;
            var regx = new Regex(regexText).Match(data);
            if (regx.Success)
            {
                s = SGLMState.Handled;

                // NVCZ kod se musi optimalizovat do lepsi podoby aby to bylo unoverzalni
                string compCD = regx.Groups["MATCD"].Value.TrimEnd();
                string batch = regx.Groups["BATCHCD"].Value.Trim();
                string sn = regx.Groups["BATCHSN"].Value.Trim();

                bool pbSnOnly = string.IsNullOrEmpty(batch) && !string.IsNullOrEmpty(sn);
                bool pbBatchAndSn = !string.IsNullOrEmpty(batch) && !string.IsNullOrEmpty(sn);
                bool pbCompAndBatch = !string.IsNullOrEmpty(compCD) && !string.IsNullOrEmpty(batch);

                BusInputBatchSerial bibSn = null;
                BusInputBatch bib = null;

                // tady by se melo osetrit co nacitam za kod. pokud sn tak najdu prvni inputbatchsn a inputbatch abych vedel soucastku, pokud kod soucastku a sarze tak musim hledat prvni soucastku v kusovniku a pak dotahovat sarzi

                // pokud by me dosla v kodu sarze a sn nebo sn sarze mel bych prvni hledat sarzi a sn a potom se divat na komponentu

                // najdi soucastku v ciseliku
                m_CurrentComponent = GetFirstUnMatchedComponentFromBom(compCD);

                if (SetError(m_CurrentComponent != null, LogMsg.SMT_ComponentUnwanted, true, sn, batch, compCD))
                {
                    if (m_loadReferenciesForSlot)
                    {
                        m_positionIDList = GetAllPositionsForCode(compCD, m_CurrentComponent.MachineID, m_CurrentComponent.MachineSideCD, m_CurrentComponent.RequestedSlot);
                    }
                    else
                        m_positionIDList = GetAllPositionsForCode(compCD);
                    bool addToCollection = false;
                    s = CheckComponent(m_CurrentComponent, out addToCollection);
                    if ((s & SGLMState.OK) == SGLMState.OK)
                    {
                        // najdi prvni komponentu co nema match
                        var cc = GetFirstUnMatchedComponentFromBom(compCD);
                        // mam neco?
                        if (cc != null)
                            m_CurrentComponent = cc.Clone();
                        else
                        {
                            Message = Log(LogMsg.SMT_ComponentAlreadyInList, compCD);
                            return SGLMState.Handled | SGLMState.Fail | SGLMState.ResetIndex;
                        }

                        // najdi inputbatch
                        bib = m_inputBatchService.GetInputBatch(m_dxSession, batch, m_CurrentComponent.ComponentID, true);

                        // pokud neexistuje a mam zalozit tak to udelej
                        if (bib == null && CreateInputBatch(batch, m_CurrentComponent.ComponentID))
                            bib = m_inputBatchService.GetInputBatch(m_dxSession, batch, m_CurrentComponent.ComponentID, true);

                        var inputBatchSN = new BusInputBatchSerial(m_inputBatchService);
                        if (SetError(bib != null, LogMsg.BATCH_BatchSnNotFound, true, data, batch, sn) && m_componentCheckSvc.CanUseComponent(this, m_dxSession, inputBatchSN, bib, SetError, Log, ref tmp_message))
                        {
                            if (bib.IsBlocked)
                            {
                                Message = Log(LogMsg.INPUTBATCH_IsBlocked, bib.BatchCD, bib.ComponentCD, bib.BlockedMessage);
                                m_CurrentComponent = null;
                                bib = null;
                                return SGLMState.Handled | SGLMState.Fail;
                            }
                            // nastav sarzi do komponenty
                            m_CurrentComponent.SetInputBatch(batch, sn);

                            if (!m_checkSlot || !m_CurrentComponent.IsSlotNeeded)
                            {
                                m_CurrentComponent.SetAsMatched();
                            }
                            // pokud se ma nacitat slot (feeder) pak jestli ho mas nacteny dej do seznamu a nastav IsMatch
                            else if (m_CurrentComponent.SlotMatched)
                            {
                                m_CurrentComponent.SetAsMatched();
                            }
                            else
                                m_waitingForSlot = true;

                        }
                        else
                        {
                            s = SGLMState.Handled | SGLMState.Fail;
                            Message = tmp_message;
                        }
                    }
                    if (m_CurrentComponent.Matched && addToCollection)
                    {
                        foreach (long position in m_positionIDList)
                        {
                            BusItem component;
                            if (!m_CurrentComponent.IsSlotNeeded)
                                component = Session.GlobalContext.BOMComponents.Where(x => x.PositionID == position && x.ComponentCD == m_CurrentComponent.ComponentCD).FirstOrDefault();
                            else
                                component = Session.GlobalContext.BOMComponents.Where(x => x.PositionID == position && x.ComponentCD == m_CurrentComponent.ComponentCD && x.FullRequestedSlot.Equals(m_CurrentComponent.FullRequestedSlot)).FirstOrDefault();
                            component.SetInputBatch(batch, sn);
                            component.SetInputBatchID(bib.OID);
                            component.SetAsMatched();
                            SetGlobalCollectionItem(m_CurrentComponent);
                            Session.CycleContext.Components.Add(component);
                        }
                        Message = Log(LogMsg.BOM_ITEM_ComponentLoaded, m_CurrentComponent.ComponentCD);
                        Session.Messenger.Send<GlobalCollectionBusItemCollectionChanged>(new GlobalCollectionBusItemCollectionChanged(Session.GlobalContext.BOMComponents));
                        //nutno este otestovat, jestli se to nekde nezhrouti
                        //m_CurrentComponent = null;
                    }
                }
            }
            // jestli cekam na slot a mam komponentu
            return s;
        }

        private SGLMState HandlePositionData(string data)
        {
            // slot bude v regexu
            var slotRegx = new Regex(m_slotRegEx).Match(data);
            string machineid = slotRegx.Groups["MachineNUM"].Value.TrimEnd();
            string side = slotRegx.Groups["Side"].Value.TrimEnd();
            string slot = slotRegx.Groups["PosNUM"].Value.TrimEnd();
            return HandlePositionData(machineid, side, slot);
        }
        private SGLMState HandlePositionData(string machineid, string side, string slot)
        {
            SGLMState s = SGLMState.NotHandled;
            if (m_waitingForSlot && m_CurrentComponent != null)
            {
                Message = Log(LogMsg.CUSTOM_INFO_MSG, "Zacinam zpracovavat slotove data");
                s = SGLMState.Handled | SGLMState.ResetIndex;
                // najdi komponentu na machineid, side a slotu
                var c = GetComponentFromBom(m_CurrentComponent.ComponentCD, machineid, side, slot);
                if (c != null)
                {
                    var batch = m_CurrentComponent.InputBatchCD;
                    var sn = m_CurrentComponent.InputBatchSerialCD;
                    m_CurrentComponent = c;
                    m_CurrentComponent.SetInputBatch(batch, sn);
                    m_CurrentComponent.SetUsedSlot(slot);

                    if (m_CurrentComponent.SlotMatched)
                    {
                        foreach (var position in m_positionIDList)
                        {
                            BusItem component;
                            if (!m_CurrentComponent.IsSlotNeeded)
                                component = Session.GlobalContext.BOMComponents.Where(x => x.PositionID == position && x.ComponentCD == m_CurrentComponent.ComponentCD).FirstOrDefault();
                            else
                                component = Session.GlobalContext.BOMComponents.Where(x => x.PositionID == position && x.ComponentCD == m_CurrentComponent.ComponentCD && x.FullRequestedSlot.Equals(m_CurrentComponent.FullRequestedSlot)).FirstOrDefault();
                            if (component != null)
                            {
                                component.SetInputBatch(m_CurrentComponent.InputBatchCD, m_CurrentComponent.InputBatchSerialCD);
                                component.SetInputBatchID(m_CurrentComponent.InputBatchID);
                                component.SetAsMatched();
                                SetGlobalCollectionItem(m_CurrentComponent);
                                Session.CycleContext.Components.Add(component);
                            }
                        }
                        Message = Log(LogMsg.BOM_ITEM_SlotChecked, m_CurrentComponent.FullRequestedSlot);
                        Session.Messenger.Send<GlobalCollectionBusItemCollectionChanged>(new GlobalCollectionBusItemCollectionChanged(Session.GlobalContext.BOMComponents));
                        m_CurrentComponent = null;
                        m_waitingForSlot = false;
                        s |= SGLMState.OK;
                    }
                    else
                    {
                        Message = Log(LogMsg.BOM_ITEM_ComponentForIncorrectSlot, m_CurrentComponent.ComponentCD, machineid, side, slot);
                        s = SGLMState.Handled | SGLMState.Fail;
                    }
                }
                else
                {
                    Message = Log(LogMsg.BOM_ITEM_ComponentForIncorrectSlot, m_CurrentComponent.ComponentCD, machineid, side, slot);
                    s = SGLMState.Handled | SGLMState.Fail;
                }
            }
            return s;
        }

        private void LoadGlobalContextComponents()
        {
            if (Session.CycleContext.OperationOverride == null)
            {
                Log(LogMsg.CUSTOM_WARNING_MSG, "Není vybrána operace na modulu BOM_Item!");
                return;
            }
            using (m_dxSession.GetLock())
            {
                var _BOMComponents = from j in new XPQuery<Job>(m_dxSession.Session)
                                     join jpbi in new XPQuery<JobBomItem>(m_dxSession.Session) on j.JobBom equals jpbi.JobBom
                                     where (j.OID == Session.Job.DoJob.JobID
                                     && jpbi.RoutingPosIndex == Session.CycleContext.OperationOverride.RoutingPosIndex
                                     && jpbi.Deleted == false && jpbi.IsRequested == true && jpbi.Quantity > 0)
                                     group jpbi by new
                                     {
                                         jpbi.OID,
                                         jpbi.RoutingPosIndex,
                                         jpbi.PosIndex,
                                         MaterialID = (jpbi.Material != null) ? jpbi.Material.OID : 0,
                                         ProductID = (jpbi.Product != null) ? jpbi.Product.OID : 0,
                                         MaterialCD = (jpbi.Material != null) ? jpbi.Material.ProductCD : string.Empty,
                                         ProductCD = (jpbi.Product != null) ? jpbi.Product.ProductCD : string.Empty,
                                         MaterialName = (jpbi.Material != null) ? jpbi.Material.Name : string.Empty,
                                         ProductName = (jpbi.Product != null) ? jpbi.Product.Name : string.Empty,
                                         PositionID = (jpbi.Position != null) ? jpbi.Position.OID : 0,
                                         jpbi.Position.PositionCD,
                                         jpbi.Quantity,
                                         jpbi.BatchMustExist,
                                         jpbi.CheckSameJob,
                                         jpbi.CheckSameBatch,
                                         jpbi.CheckSameLEDBinning
                                     } into t
                                     select BusItem.Create(t.Key.OID, t.Key.RoutingPosIndex, t.Key.PosIndex, t.Key.MaterialID,
                                        t.Key.ProductID, t.Key.MaterialCD, t.Key.ProductCD, t.Key.MaterialName, t.Key.ProductName,
                                        t.Key.PositionID, t.Key.PositionCD, t.Key.Quantity, t.Key.BatchMustExist,
                                        t.Key.CheckSameJob, t.Key.CheckSameBatch, t.Key.CheckSameLEDBinning);

                Message = Log(LogMsg.CUSTOM_INFO_MSG, $"Zacinam dotahovat material z Jobu {Session.Job.DoJob.JobID} pro routingovou pozici {Session.CycleContext.OperationOverride.RoutingPosIndex}");

                foreach (var component in _BOMComponents)
                {
                    if (component.MaterialID != 0)
                    {
                        katalog.Load(component.MaterialID);
                        component.IsPaste = katalog.GetValue<bool>("IsPaste", false, true);
                    }
                    Message = Log(LogMsg.CUSTOM_INFO_MSG, $"Kod materialu {component.ComponentCD}, reference {component.PositionCD}, mnozstvi {component.Quantity}");
                    m_globalContextComponents.Add(component);
                }
            }
            Message = Log(LogMsg.CUSTOM_INFO_MSG, "Dokoncil sem dotaz na material z jobu");

        }
        protected override void SendActualStep()
        {
            IEnumerable<BusItem> responseBusItemEnumerable;
            if (m_sendOnlyOneComponent)
            {
                responseBusItemEnumerable = Session.GlobalContext.BOMComponents.Where(x => x.Matched == false).Take(1);
            }
            else
            {
                responseBusItemEnumerable = Session.GlobalContext.BOMComponents;
            }
            if (Session.GlobalContext.CurrentMachineProgram.IsSet)
            {
                Session.Messenger.Send(new HttpApiResponseMessage(new ApiResponseDataCheckActualStepComponents()
                {
                    ActualStep = this.ModuleCD,
                    GlobalContextComponents = responseBusItemEnumerable,
                    CheckSlotActive = m_checkSlot,
                    Prepared = Prepared
                }));
            }
            else
            {
                Session.Messenger.Send(new HttpApiResponseMessage(new ApiResponseDataCheckActualStepComponents()
                {
                    ActualStep = this.ModuleCD,
                    GlobalContextComponents = responseBusItemEnumerable,
                    CheckSlotActive = m_checkSlot,
                    Prepared = Prepared
                }));
            }
        }

        /// <summary>
        /// prepise index v kolekci GlobalContext.BOMComponents pokud v ni jiz existuje takovy zaznam
        /// </summary>
        /// <param name="item"></param>
        public void SetGlobalCollectionItem(BusItem item)
        {
            if (item.IsSlotNeeded)
            {
                var compsToBeUpdated = Session.GlobalContext.BOMComponents.Where(x => x.ComponentID == item.ComponentID && x.FullRequestedSlot == item.FullRequestedSlot).Select(x => x).ToList();
                for (int i = 0; i < compsToBeUpdated.Count; i++)
                {
                    compsToBeUpdated[i].Matched = true;
                }
            }
            else
            {
                var compsToBeUpdated = Session.GlobalContext.BOMComponents.Where(x => x.ComponentID == item.ComponentID).Select(x => x).ToList();
                for (int i = 0; i < compsToBeUpdated.Count; i++)
                {
                    compsToBeUpdated[i].Matched = true;
                }
                //Session.GlobalContext.BOMComponents.Where(x => x.ComponentID == item.ComponentID).Select(x => { x.Matched = item.Matched; return x; }).FirstOrDefault();
            }
            return;
        }
        #endregion
    }
}