/***************************************************************************
 *                          Zanoza Modeler v2.x                            *
 *      This is unpublished propietary source code of Zanoza Software.     *
 *      The copyright notice does not evidence any actual or intended      *
 *                    publication of such source code.                     *
 *                                                                         *
 *                Copyright (c) 2002-2003 Zanoza Software.                 *
 *                                                                         *
 *                        All rights reserved.                             *
 ***************************************************************************
 *--------------------------------------------------------------------------
 * @author:   Oleg M.
 *--------------------------------------------------------------------------
 * @purpose:  ZModeler 2.x Scene navigation helpers
 *--------------------------------------------------------------------------
 * @histroy: 31.07.2003. Created
 * @histroy: 08.09.2003. Manipulators navigation added
 */
#ifndef scenenavigationhelper_h_included
#define scenenavigationhelper_h_included

#include <zmodeler.h>
#include <scene/IMeshNode.h>
#include <scene/IPolyMesh.h>
#include <scene/IManipulateable.h>
#include <scene/ITransformable.h>
#include <shared/INodeListControl.h>

namespace scene
{
  DLL_LINKAGE bool subsetConvenientStatus(const DWORD dwStat, 
                                          const core::eLevel level,
                                          const bool bSelOn);
  DLL_LINKAGE bool subLevelEditableStatus( const DWORD dwStat, const bool bSelOn);
  inline bool accessConvenientStatus(const DWORD dwStatus)
  {
    return (dwStatus & (STATUS_ENABLED | STATUS_HIDDEN)) == STATUS_ENABLED;
  }
  //bottom to top (child->parent->...->root)
  DLL_LINKAGE void getFullTransform(scene::INode* pNode, ZMatrix& trans);
  //top to bottom (root->child->...->leaf)
  DLL_LINKAGE void getRevFullTransform(scene::INode* pNode, ZMatrix& trans);
  DLL_LINKAGE void getRelativeTransform(scene::INode* pNodeChild, scene::INode* pTopParent, ZMatrix& trans);
  //world-space to node-space transform matrix;
  DLL_LINKAGE void getWorldToNodeTransform(scene::INode* pNode, ZMatrix& trans);
  //node-space to world-space transform matrix;
  DLL_LINKAGE void getNodeToWorldTransform(scene::INode* pNode, ZMatrix& trans);
  //------------------------------------------------------------------
  //
  // @Description : Subset iterator class
  // @Purpose     : Simplifies navigation through subset nodes.
  //
  //------------------------------------------------------------------
  class DLL_LINKAGE CSubsetIterator
  {
  public:
    CSubsetIterator();
    virtual ~CSubsetIterator();
  public:
    //--------------------------
    // operations:
    //--------------------------
    // initializes iterator (and subset if required). returns ZRESULT_OK on success
    ZRESULT initialize(core::IProcParams* pParams, bool bForceSubsetInit = false);
    
    //navigation:
    void    reset();
    bool    next();
    bool    prev();
    //node access:
    ZRESULT getNode(scene::INode** ppNode);
    ZRESULT getEntityBase(ZEntityBase** ppBase, scene::INode** ppOwnerNode/*optional*/);
    //node status
    bool    isAllowEditing(); //enabled, not hidden and active (or selected in SEL mode)
    DWORD   getNodeStatus();
    ZRESULT changeNodeStatus(DWORD dwAdd, DWORD dwRemove);
    ZRESULT setNodeStatus(DWORD dwStatus);
    //node transform:
    ZRESULT getNodeTransform(ZMatrix& trans);
    ZRESULT setNodeTransform(ZMatrix& trans);
    ZRESULT getITransformable(scene::ITransformable** ppTrans);
    ZRESULT getPreNodeTransform(ZMatrix& trans); //from [root, node)
    // reverse full node transform provides a matrix that convert node-space to world-space
    ZRESULT getNodeToWorldTransform(ZMatrix& trans);//getPreNodeTransform*getNodeTransform
    //converts world vector to pre-node-space vector.
    ZRESULT worldToPreNode(ZVector& vWorld, const core::eAxesMode mode, const core::eAxis axis);
    //converts world vector to node-space vector.
    ZRESULT worldToNode(ZVector& vWorld, const core::eAxesMode mode, const core::eAxis axis);
    //applies transformation to child nodes
    ZRESULT applyChildTransform(ZMatrix& matTrans);


    //node level (root has level 0)
    static  long getNodeLevel(scene::INode* pNode);
    inline  long getNodeLevel() { return getNodeLevel(m_pCurrNode); }

    //direct access:
    ZRESULT queryNode(LPCSTR iid, void** ppResult);

    //if (IMeshNode)
    ZRESULT getMeshNode(scene::IMeshNode** ppMeshNode);
    ZRESULT getMesh(scene::IMesh** ppMesh);
    // sets node's mesh. prior call to getMesh is a "must be".
    ZRESULT setMesh(scene::IMesh*  pMesh);
    ZRESULT getPolyMeshData(ZVertexBuf** ppVertBuf, ZPolyBuf** ppPolyBuf);
    // sets node's mesh data. prior call to getPolyMeshData is a "must be".
    ZRESULT setPolyMeshData(ZVertexBuf* pVertBuf, ZPolyBuf* pPolyBuf, bool bChangeVB = true, bool bChangePB = true);
    ZRESULT alterNode(DWORD dwBits);//INode->changed()

  private:
    void initDataFromNode();

    //--------------------------
    // data members:
    //--------------------------
    ZPtr<scene::CNodeCol>         m_pNodes;
    ZPtr<scene::INode>            m_pCurrNode;
    ZPtr<scene::IMeshNode>        m_pMeshNode;
    ZPtr<scene::IMesh>            m_pMesh;
    ZPtr<scene::IPolyMesh>        m_pPolyMesh;
    ZPtr<scene::IManipulator>     m_pCurrManip;
    ZPtr<scene::CManipulatorCol>  m_pManipCol;
    ZPtr<scene::IScene>           m_pScene;
    core::eLevel                  m_level;
    bool                          m_bSelMode;
    DWORD                         m_dwDeferAlterNode;
  };//class


  //------------------------------------------------------------------
  //
  // @Description : Scene nodes navigator
  // @Purpose     : Simplifies navigation through scene nodes.
  //
  //------------------------------------------------------------------
  class DLL_LINKAGE CSceneNavigator
  {
  public:
    CSceneNavigator();
    virtual ~CSceneNavigator();
  public:
    //--------------------------
    // operations:
    //--------------------------
    ZRESULT initialize(core::IProcParams* pParams, /*force access hidden and disabled?*/bool bNavigateAny = false); //returns ZRESULT_OK on success
    //navigation:
    void    reset();
    bool    next();
    bool    prev();

    //node access:
    ZRESULT getNode(scene::INode** ppNode);
    //node status
    bool    isAccessible();   //enabled, not hidden
    bool    isAllowEditing(); //enabled, not hidden and active (or selected in SEL mode)
    DWORD   getNodeStatus();
    ZRESULT changeNodeStatus(DWORD dwAdd, DWORD dwRemove);
    ZRESULT setNodeStatus(DWORD dwStatus);
    //node transform:
    ZRESULT getNodeTransform(ZMatrix& trans);
    ZRESULT setNodeTransform(ZMatrix& trans);
    ZRESULT getPreNodeTransform(ZMatrix& trans); //from root upto node's parent
    // reverse full node transform provides a matrix that convert node-space to world-space
    ZRESULT getNodeToWorldTransform(ZMatrix& trans);//getPreNodeTransform*getNodeTransform

    //node level (root has level 0)
    inline  long getNodeLevel() 
    { 
      if (m_nCurrNode >= m_seqNodes.length())
        return 0;
      else
        return CSubsetIterator::getNodeLevel(m_seqNodes[m_nCurrNode]); 
    }

    //direct access:
    ZRESULT queryNode(LPCSTR iid, void** ppResult);

    //if (IMeshNode)
    ZRESULT getMeshNode(scene::IMeshNode** ppMeshNode);
    ZRESULT getMesh(scene::IMesh** ppMesh);
    // sets node's mesh. prior call to getMesh is a "must be".
    ZRESULT setMesh(scene::IMesh*  pMesh);
    ZRESULT getPolyMeshData(ZVertexBuf** ppVertBuf, ZPolyBuf** ppPolyBuf);
    // sets node's mesh data. prior call to getPolyMeshData is a "must be".
    ZRESULT setPolyMeshData(ZVertexBuf* pVertBuf, ZPolyBuf* pPolyBuf, bool bChangeVB = true, bool bChangePB = true);
    ZRESULT alterNode(DWORD dwBits);//INode->changed()

  private:

    //--------------------------
    // data members:
    //--------------------------
    ZPtr<scene::IScene>             m_pScene;
    ZSequence<ZPtr<scene::INode> >  m_seqNodes;
    long                            m_nCurrNode;
    core::eLevel                    m_level;
    bool                            m_bSelMode;
  };//class

  //
  // helper functions for examining and colleting nodes
  //

  //-------------------------------------------------------
  // @name : ZAPICALL collectNodesByInterface
  // Collects nodes with supplied interface
  // @param Node*      pParent             : not to start with
  // @param LPCTSTR     pszIID             : IID. or NULL to collect all nodes
  // @param CNodeCol**  ppCol              : ret-val arg
  //
  // @return DLL_LINKAGE ZRESULT : 
  //-------------------------------------------------------
  DLL_LINKAGE ZRESULT ZAPICALL collectNodesByInterface(
                                        INode*      pParent,
                                        LPCTSTR     pszIID,
                                        CNodeCol**  ppCol);

  //-------------------------------------------------------
  // @name : collectNodesByMaterial
  // collects nodes that uses supplied material starting from pParent node.
  // pParent is usually scene root node
  // @param Node*       pParent            : node whose children are tested
  // @param long        nMaterial          : material to look for (or -1 to match all)
  // @param CNodeCol**  ppCol              : ret-val arg. must not be NULL!
  // @param DWORD       dwExtPass = 0      : poly-extensions bits required to pass test
  // @param DWORD       dwExtFail = 0      : poly-extension bits enough to fail test
  //
  // @return ZRESULT : ZRESULT_OK on success
  //-------------------------------------------------------
  DLL_LINKAGE ZRESULT ZAPICALL collectNodesByMaterial(
                                        INode*      pParent, 
                                        long        nMaterial,
                                        CNodeCol**  ppCol,
                                        DWORD       dwExtPass = 0,
                                        DWORD       dwExtFail = 0);


  // @Name        : class CDisplayNodesByNameDialog
  // @Purpose     : dialogbox for selecting scene nodes by name
  //              : You can overload OnOK to perform whatever
  //              : you need with selected nodes.
  class DLL_LINKAGE CDisplayNodesByNameDialog : public CDialog
  {
  public:
    CDisplayNodesByNameDialog(CWnd* pParent, LPCTSTR pszTitle=NULL, LPCTSTR pszOKButton=NULL);
    virtual ~CDisplayNodesByNameDialog(){}
  public:
    DECLARE_MESSAGE_MAP()
    BOOL OnInitDialog();
  public:

    afx_msg void onAll();
    afx_msg void onNone();
    afx_msg void onInvert();

    afx_msg void onListAll();
    afx_msg void onListNone();
    afx_msg void onListCustom();
    afx_msg void onSearch();
    ZRESULT collectNodes(scene::INode* pN);
    ZRESULT getSelection(scene::CNodeCol** ppCol) { return m_pSel.CopyTo(ppCol); }
  //overloads:
    virtual void OnOK() { EndDialog(IDOK); }
    virtual ZRESULT getRootNode(scene::INode** ppRoot) { return ZRESULT_NOT_IMPLEMENTED; }
    
  protected:
    ZPtr<shared::INodeListControl>  m_pList;
    ZPtr<scene::CNodeCol>           m_pSel;
    ZPtr<scene::CNodeCol>           m_pNodes;

    ZString                         m_strTitle, m_strOKButton;
  };//class
};//scene


#endif //scenenavigationhelper_h_included



