/**
 * get target id paths for all targets from target tree.
 *
 * @param           [in] rtIdMap: id map with id -> id path data
 * @see             
*/
BOOL CInstanceTree::GetTargetsFromTargetTree(TStringList& listTargets)
{
    // get all targets as id paths
    SAFEARRAY* parrTargets;
    m_pProjectManager->getAllTargetsAsIdPaths(&parrTargets);

    BSTR HUGEP *pbstr;
    BSTR bstr;
    HRESULT hr;
    unsigned long i;

    // Get a pointer to the elements of the array.
    hr = ::SafeArrayAccessData(parrTargets, (void HUGEP**)&pbstr);
    if(FAILED(hr))
    {
        return FALSE;
    }

    CString strIdPath;
    for (i = 0; i < (parrTargets->rgsabound[0]).cElements; i++)
    {
        bstr = pbstr[i];
        strIdPath = (CString)bstr;
        listTargets.AddTail(strIdPath);
    }

    ::SafeArrayUnaccessData(parrTargets);		
    ::SafeArrayDestroy(parrTargets);
 
    return TRUE;
}
BOOL CInstanceTree::UpdateTargets()
{
    // only do update if something has changed in the target view
    if (!(m_pProjectManager->GetTargetTree())->m_bTargetTreeChanged)
    {
        return TRUE;
    }

    BOOL ret;
    CXMLDocument    tTargetDoc;
    TStringList listNewTargets;
    CXMLNode nodeTargetRoot;
    CXMLNode nodeInstanceRoot;

    // update lists
    TStringList listUpdateChanged;
    TStringList listUpdateNew;
    TStringList listUpdateDeleted;

    (m_pProjectManager->GetTargetTree())->m_bTargetTreeChanged = FALSE;

    // get instance tree root node
    if (!m_domDocument.GetRootNode(nodeInstanceRoot))
    {
        return FALSE;
    }

    // get root node of target view
    IUnknown*   pTmp = NULL;
    HRESULT hr = m_pProjectManager->GetTargetViewDOM(&pTmp);
    if(hr != S_OK)
    {
        return FALSE;
    }
    tTargetDoc.SetIXMLDocument(pTmp);
    pTmp->Release();
    // add target nodes as children
    if(!tTargetDoc.GetRootNode(nodeTargetRoot))
    {
        return FALSE;
    }

    // get new targets from target view
    if (!GetTargetsFromTargetTree(listNewTargets))
    {
        return FALSE;
    }

    // empty xml tree
    nodeInstanceRoot.RemoveAllChilds();

    // mark all nodes not used:
    POSITION posH = m_mapInstanceTargets.GetStartPosition();
    while(posH)
    {
        CString strId;
        TInstanceTargetInfo* pInfo;
        m_mapInstanceTargets.GetNextAssoc(posH, strId, pInfo);
        if (pInfo)
        {
            pInfo->bUsed = FALSE;
        }
    }
    


    // look at all new targets, hang targets into the tree:
    // test if target is a new target or the attributes have changed or it is the same
    // in the last two cases, take the old node and only change attributes if necessary
    POSITION posNewTargets = listNewTargets.GetHeadPosition();
    while(posNewTargets)
    {
        CXMLNode nodeTarget;
        CXMLNode nodeInstance;
        CXMLNode nodeLink;

        // attributes of the target node
        CString     strTText;                // node text
        CString     strTId;                  // node id
        CString     strTType;                // node type (KAD type)
        CString     strTAddress;             // connect info
        CString     strTUserAddress;         // user connect info
        CString     strTConsoleAddress;      // console address
        CString     strTAssignedResource;    // assigned resource
        CString     strTSource;              // source file for add on action
        
        CString     strParseSource;         // parser source help var
        CString     strParseSourceNew;      // parser source
        CString     strInstType;             // type of the instance node

        CString     strIdPathTarg;          // id path of target node in target tree
        CString     strIdPathInst;          // id path of target instance in instance tree
        CString     strTargetId;
        CString     strWaitForTarget;
        
        strIdPathTarg = listNewTargets.GetNext(posNewTargets);

        strTargetId = strIdPathTarg;
        int iFind = strTargetId.ReverseFind(CE_XML_IDPATH_SEP_CHAR);
        ASSERT(iFind>0);
        if (iFind>0)
        {
            strTargetId = strTargetId.Mid(iFind+1);
        }

        // get target node
        ret = nodeTargetRoot.GetNodeFromIdPath(strIdPathTarg, nodeTarget);
        ASSERT(ret);
        if (!ret)
        {
            continue;
        }

        // get attributes of the target node
        nodeTarget.GetAttribute(CE_XMLATTR_TEXT, strTText);
        nodeTarget.GetAttribute(CE_XMLATTR_ID, strTId);
        nodeTarget.GetAttribute(CE_XMLATTR_TYPE, strTType);
        nodeTarget.GetAttribute(CE_XMLATTR_ADDR, strTAddress);
        nodeTarget.GetAttribute(CE_XMLATTR_USERADDR, strTUserAddress);
        nodeTarget.GetAttribute(CE_XMLATTR_CONSOLE_ADDR, strTConsoleAddress);
        nodeTarget.GetAttribute(CE_XMLATTR_RESOURCE, strTAssignedResource);
        nodeTarget.GetAttribute(CE_XMLATTR_SOURCE, strTSource);
        nodeTarget.GetAttribute(CE_XMLATTR_WAIT_TARGET_CONN , strWaitForTarget);

        strInstType = strTType + CE_XML_INST_ADD;
        strParseSource = strTId + _T(".") + CE_INSTANCE_EXT;
        strParseSourceNew = CString(CE_GEN_PATH) + _T("\\") + strTId + _T("\\") + strParseSource;

        // does node already exist in instance tree:
        TInstanceTargetInfo* pInstTargetInfo = NULL;
        CString strLowerId = strTargetId;
        strLowerId.MakeLower();
        if (m_mapInstanceTargets.Lookup(strLowerId, pInstTargetInfo))
        {
            // *** existing node ***
            ASSERT(pInstTargetInfo);
            pInstTargetInfo->bUsed = TRUE;
            nodeInstance = pInstTargetInfo->xmlNode;
            ret = nodeInstanceRoot.AppendChild(nodeInstance, TRUE);
            ASSERT(ret);

            // check if attributes have changed
            // get instance node attributes
            CString strInstText;
            CString strInstId;
            //CString strInstType;
            CString strInstAddress;
            CString strInstUserAddress;
            CString strInstConsoleAddress;
            CString strInstAssignedResource;
            CString strInstSource;

            nodeInstance.GetAttribute(CE_XMLATTR_TEXT, strInstText);
            nodeInstance.GetAttribute(CE_XMLATTR_ID, strInstId);
            //nodeInstance.GetAttribute(CE_XMLATTR_TYPE, strInstType); // type can't change
            nodeInstance.GetAttribute(CE_XMLATTR_ADDR, strInstAddress);
            nodeInstance.GetAttribute(CE_XMLATTR_USERADDR, strInstUserAddress);
            nodeInstance.GetAttribute(CE_XMLATTR_CONSOLE_ADDR, strInstConsoleAddress);
            nodeInstance.GetAttribute(CE_XMLATTR_RESOURCE, strInstAssignedResource);
            nodeInstance.GetAttribute(CE_XMLATTR_SOURCE, strInstSource);
            
            if ((strInstText.CompareNoCase(strTText)!=0)
                || (strInstId.CompareNoCase(strTId)!=0)
                //|| (strInstType.CompareNoCase(strType)!=0)
                || (strInstAddress.CompareNoCase(strTAddress)!=0)
                || (strInstConsoleAddress.CompareNoCase(strTConsoleAddress)!=0)
                || (strInstAssignedResource.CompareNoCase(strTAssignedResource)!=0)
                || (strInstSource.CompareNoCase(strTSource) != 0))
            {
                // node has changed -> update nodes
                nodeInstance.SetAttribute(CE_XMLATTR_TEXT, strTText);
                nodeInstance.SetAttribute(CE_XMLATTR_ID, strTId);
                //nodeInstance.SetAttribute(CE_XMLATTR_TYPE, strType);
                nodeInstance.SetAttribute(CE_XMLATTR_ADDR, strTAddress);
                nodeInstance.SetAttribute(CE_XMLATTR_USERADDR, strTUserAddress);
                nodeInstance.SetAttribute(CE_XMLATTR_CONSOLE_ADDR, strTConsoleAddress);
                nodeInstance.SetAttribute(CE_XMLATTR_RESOURCE, strTAssignedResource);
                nodeInstance.SetAttribute(CE_XMLATTR_SOURCE, strTSource);

                listUpdateChanged.AddTail(pInstTargetInfo->strIdPath);
            }
           
        }
        else // *** new node ***
        {
            if(!m_domDocument.CreateNode(nodeInstance, CE_XMLTAG_NODE))
            {
                continue;
            }

            // set attributes of target instance node
            nodeInstance.SetAttribute(CE_XMLATTR_TEXT, strTText);
            nodeInstance.SetAttribute(CE_XMLATTR_ID, strTId);
            nodeInstance.SetAttribute(CE_XMLATTR_ADDR, strTAddress);
            nodeInstance.SetAttribute(CE_XMLATTR_USERADDR, strTUserAddress);
            nodeInstance.SetAttribute(CE_XMLATTR_CONSOLE_ADDR, strTConsoleAddress);
            nodeInstance.SetAttribute(CE_XMLATTR_RESOURCE, strTAssignedResource);
            nodeInstance.SetAttribute(CE_XMLATTR_TARGET_TYPE, strTType);
            nodeInstance.SetAttribute(CE_XMLATTR_SOURCE, strTSource);

            nodeInstance.SetAttribute(CE_XMLATTR_TYPE, strInstType);
            if (!strWaitForTarget.IsEmpty())
            {
                nodeInstance.SetAttribute(CE_XMLATTR_WAIT_TARGET_CONN, strWaitForTarget);
            }

            // create new instance info struct
            ASSERT(pInstTargetInfo==NULL);
            pInstTargetInfo = new TInstanceTargetInfo;
            ASSERT(pInstTargetInfo);
            if (!pInstTargetInfo)
            {
                continue;
            }

            ret = nodeInstanceRoot.AppendChild(nodeInstance, TRUE);
            ASSERT(ret);

            nodeInstance.GetIdPath(strIdPathInst);
            pInstTargetInfo->strIdPath = strIdPathInst;
            pInstTargetInfo->strTargetId = strTId;
            pInstTargetInfo->xmlNode = nodeInstance;
            pInstTargetInfo->bUsed = TRUE;

            strLowerId = strTId;
            strLowerId.MakeLower();

            m_mapInstanceTargets.SetAt(strLowerId, pInstTargetInfo);

            // add to update list (new node)
            listUpdateNew.AddTail(strIdPathInst);

           

            // now create target link node: the link that will be replaced by compiler outpu
            if((!m_domDocument.CreateNode(nodeLink, CE_XMLTAG_LINK))
                ||(!nodeInstance.AppendChild(nodeLink)) )
            {
                continue;
            }

            nodeLink.SetAttribute(CE_XMLATTR_PARSERSOURCE, strParseSourceNew);
            nodeLink.SetAttribute(CE_XMLATTR_ID, strTId);

            TSourceFileInfo* pFileInfo;
            pFileInfo = CreateSourceFileInfo(strParseSourceNew, nodeLink, "");
            SourceFileMap_SetAt(strParseSourceNew, pFileInfo, m_mapSourceFiles);

            AddSourceFileToReparse(strParseSourceNew);
        }
    }

   
    

    // find deleted nodes:
    posH = m_mapInstanceTargets.GetStartPosition();
    while(posH)
    {
        CString strId;
        TInstanceTargetInfo* pInfo;
        m_mapInstanceTargets.GetNextAssoc(posH, strId, pInfo);
        if (pInfo)
        {
            if (pInfo->bUsed == FALSE)
            {
                listUpdateDeleted.AddTail(pInfo->strIdPath);
                delete pInfo;
                m_mapInstanceTargets.RemoveKey(strId);
            }
        }
    }

    if (m_bInit)
    {
        return TRUE;
    }

    // send update messages
    POSITION lPos;
    lPos = listUpdateDeleted.GetHeadPosition();
    while(lPos)
    {
        CString strIdPath = listUpdateDeleted.GetNext(lPos);
        if (!strIdPath.IsEmpty())
        {
            FireUpdateTree(strIdPath, eUpdateDelete);
            CString strId = strIdPath;
            int iFind = strId.ReverseFind(CE_XML_IDPATH_SEP_CHAR);
            ASSERT(iFind>0);
            if (iFind>0)
            {
                strId = strId.Mid(iFind+1);
            }
            CComBSTR sId = strId;
            m_pProjectManager->Fire_TargetInstanceRemoved(sId);
        }
    }
    lPos = listUpdateChanged.GetHeadPosition();
    while(lPos)
    {
        CString strIdPath = listUpdateChanged.GetNext(lPos);
        if (!strIdPath.IsEmpty())
        {
            FireUpdateTree(strIdPath, eUpdateAttributes);
            CString strId = strIdPath;
            int iFind = strId.ReverseFind(CE_XML_IDPATH_SEP_CHAR);
            ASSERT(iFind>0);
            if (iFind>0)
            {
                strId = strId.Mid(iFind+1);
            }
            CComBSTR sId = strId;
            CComBSTR sIdPath = strIdPath;
            m_pProjectManager->Fire_TargetInstanceAdded(sId, sIdPath);
        }
    }
    lPos = listUpdateNew.GetHeadPosition();
    while(lPos)
    {
        CString strIdPath = listUpdateNew.GetNext(lPos);
        if (!strIdPath.IsEmpty())
        {
            FireUpdateTree(strIdPath, eUpdateInsert);
            CString strId = strIdPath;
            int iFind = strId.ReverseFind(CE_XML_IDPATH_SEP_CHAR);
            ASSERT(iFind>0);
            if (iFind>0)
            {
                strId = strId.Mid(iFind+1);
            }
            CComBSTR sId = strId;
            CComBSTR sIdPath = strIdPath;
            m_pProjectManager->Fire_TargetInstanceAdded(sId, sIdPath);
        }
    }

    Reparse(FALSE);
    
    return TRUE;
}