//
// relation.cpp : Implementation of ClassRelationshipPage
//
// Jon Newman <jonn@microsoft.com>
// Copyright (c) Microsoft Corporation 1997
//

#include "stdafx.h"

#include "macros.h"
USE_HANDLE_MACROS("SCHMMGMT(relation.cpp)")

#include "compdata.h"
#include "schmutil.h"

#include "relation.h"
#include "select.h"



const CDialogControlsInfo ctrls[] =
{
    { IDC_CLASS_REL_AUX_CLASSES,    g_AuxiliaryClass,   FALSE },
    { IDC_CLASS_REL_AUX_ADD,        g_AuxiliaryClass,   FALSE },
    { IDC_CLASS_REL_SUPER_CLASSES,  g_Superiors,        FALSE },
    { IDC_CLASS_REL_SUPER_ADD,      g_Superiors,        FALSE },
} ;


const DWORD ClassRelationshipPage::help_map[] =
{
    IDI_CLASS,                          NO_HELP,
    IDC_CLASS_REL_NAME_STATIC,          NO_HELP,
    IDC_CLASS_REL_PARENT_EDIT,          IDH_CLASS_REL_PARENT_EDIT,
    IDC_CLASS_REL_AUX_CLASSES,          IDH_CLASS_REL_AUX_CLASSES,
    IDC_STATIC_SYSTEMONLY_AUXILIARY,    NO_HELP,
    IDC_CLASS_REL_AUX_ADD,              IDH_CLASS_REL_AUX_ADD,
    IDC_CLASS_REL_AUX_REMOVE,           IDH_CLASS_REL_AUX_REMOVE,
    IDC_CLASS_REL_SUPER_CLASSES,        IDH_CLASS_REL_SUPER_CLASSES,
    IDC_STATIC_SYSTEMONLY_SUPERIOR,     NO_HELP,
    IDC_CLASS_REL_SUPER_ADD,            IDH_CLASS_REL_SUPER_ADD,
    IDC_CLASS_REL_SUPER_REMOVE,         IDH_CLASS_REL_SUPER_REMOVE,
    IDC_CLASS_REL_SYSCLASS_STATIC,      NO_HELP,
    0,0
};


ClassRelationshipPage::ClassRelationshipPage(
    ComponentData *pScope,
    LPDATAOBJECT lpDataObject ) :
        CPropertyPage(ClassRelationshipPage::IDD)
        , m_pIADsObject( NULL )
        , fSystemClass( FALSE )
        , m_pSchemaObject( NULL )
        , m_pScopeControl( pScope )
        , m_lpScopeDataObj( lpDataObject )
{
    ASSERT( NULL != m_pScopeControl );
    ASSERT( NULL != lpDataObject );
}

ClassRelationshipPage::~ClassRelationshipPage()
{
    if (NULL != m_pIADsObject)
            m_pIADsObject->Release();
    if (NULL != m_pSchemaObject) {
        m_pScopeControl->g_SchemaCache.ReleaseRef( m_pSchemaObject );
    }
}

void
ClassRelationshipPage::Load(
    Cookie& CookieRef
) {

    //
    // Store the cookie object pointer.
    //

    m_pCookie = &CookieRef;
    return;

}

BOOL
ClassRelationshipPage::OnInitDialog()
{
    HRESULT hr = S_OK;
    ASSERT( NULL == m_pIADsObject && m_szAdsPath.IsEmpty() );

    //
    // Get the schema cache object and the actual ADS object.
    //

    m_pSchemaObject = m_pScopeControl->g_SchemaCache.LookupSchemaObjectByCN(
                        m_pCookie->strSchemaObject,
                        SCHMMGMT_CLASS );

    if ( m_pSchemaObject ) {

        m_pScopeControl->GetSchemaObjectPath( m_pSchemaObject->commonName, m_szAdsPath );

        if ( !m_szAdsPath.IsEmpty() ) {

           hr = ADsGetObject( (LPWSTR)(LPCWSTR)m_szAdsPath,
                              IID_IADs,
                              (void **)&m_pIADsObject );

           ASSERT( SUCCEEDED(hr) );
        }

    }

    //
    // If we have no ADS object, we should error out!
    //

    if ( !m_pIADsObject ) {
        DoErrMsgBox( ::GetActiveWindow(), TRUE, IDS_ERR_NO_SCHEMA_OBJECT );
                ASSERT(FALSE);
        return TRUE;
    }

    //
    // get the current values.
    //

    VARIANT AdsResult;
    VariantInit( &AdsResult );

    //
    // ObjectName
    //

    hr = m_pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_DisplayName),
                          &AdsResult );

    if ( SUCCEEDED( hr ) ) {
      ASSERT( AdsResult.vt == VT_BSTR );
      ObjectName = AdsResult.bstrVal;
      VariantClear( &AdsResult );
    }

    //
    // Parent Class.
    //

    hr = m_pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_SubclassOf),
                          &AdsResult );

    if ( SUCCEEDED( hr ) ) {

      ASSERT( AdsResult.vt == VT_BSTR );
      ParentClass = AdsResult.bstrVal;
      VariantClear( &AdsResult );
    }

    //
    // SysClass
    //

    hr = m_pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_SystemOnly),
                           &AdsResult );

    if ( SUCCEEDED( hr ) ) 
    {
      ASSERT( AdsResult.vt == VT_BOOL );
      fSystemClass = AdsResult.boolVal;

      if ( fSystemClass ) 
      {
        SysClassString = g_SysClassString;
      } 
      else 
      {
        SysClassString = L"";
      }

      VariantClear( &AdsResult );

    } 
    else 
    {
      SysClassString = L"";
    }

    //
    // Determine the auxiliary classes
    //

    VARIANT varClasses;
    VariantInit( &varClasses );

    hr = m_pIADsObject->GetEx( g_AuxiliaryClass, &varClasses );
    ASSERT( SUCCEEDED(hr) || E_ADS_PROPERTY_NOT_FOUND == hr );
    if( SUCCEEDED(hr) )
    {
      hr = VariantToStringList( varClasses, strlistAuxiliary );
      ASSERT( SUCCEEDED(hr) || E_ADS_PROPERTY_NOT_FOUND == hr );
    }
    VariantClear( &varClasses );

    hr = m_pIADsObject->GetEx( g_SystemAuxiliaryClass, &varClasses );
    ASSERT( SUCCEEDED(hr) || E_ADS_PROPERTY_NOT_FOUND == hr );
    if( SUCCEEDED(hr) )
    {
      hr = VariantToStringList( varClasses, strlistSystemAuxiliary );
      ASSERT( SUCCEEDED(hr) || E_ADS_PROPERTY_NOT_FOUND == hr );
    }
    VariantClear( &varClasses );

    //
    // Determine the superior classes
    //

    hr = m_pIADsObject->GetEx( g_Superiors, &varClasses );
    ASSERT( SUCCEEDED(hr) || E_ADS_PROPERTY_NOT_FOUND == hr );
    
    if( SUCCEEDED(hr) )
    {
        hr = VariantToStringList( varClasses, strlistSuperior );
        ASSERT( SUCCEEDED(hr) || E_ADS_PROPERTY_NOT_FOUND == hr );
    }
    VariantClear( &varClasses );
    
    hr = m_pIADsObject->GetEx( g_SystemSuperiors, &varClasses );
    ASSERT( SUCCEEDED(hr) || E_ADS_PROPERTY_NOT_FOUND == hr );
    
    if( SUCCEEDED(hr) )
    {
        hr = VariantToStringList( varClasses, strlistSystemSuperior );
        ASSERT( SUCCEEDED(hr) || E_ADS_PROPERTY_NOT_FOUND == hr );
    }
    VariantClear( &varClasses );


    hr = DissableReadOnlyAttributes( this, m_pIADsObject, ctrls, sizeof(ctrls)/sizeof(ctrls[0]) );
    ASSERT( SUCCEEDED(hr) );     // shouldn't fail, but unimportant, so ignore error


    // This calls must be done before DDX binding
    m_listboxAuxiliary.InitType( m_pScopeControl,
                                 SELECT_AUX_CLASSES,
                                 IDC_CLASS_REL_AUX_REMOVE,
                                 &strlistSystemAuxiliary,
                                 IDC_STATIC_SYSTEMONLY_AUXILIARY
                               );

    m_listboxSuperior.InitType(  m_pScopeControl,
                                 SELECT_CLASSES,
                                 IDC_CLASS_REL_SUPER_REMOVE,
                                 &strlistSystemSuperior,
                                 IDC_STATIC_SYSTEMONLY_SUPERIOR
                              );

    CPropertyPage::OnInitDialog();

    return TRUE;
}



BOOL
ClassRelationshipPage::OnSetActive()
{
   // always enable the Apply button
   SetModified(TRUE);

   return TRUE;
}



void
ClassRelationshipPage::DoDataExchange(
    CDataExchange *pDX
) {

        HRESULT hr = S_OK;

    CPropertyPage::DoDataExchange( pDX );

        //{{AFX_DATA_MAP(ClassRelationshipPage)
        DDX_Control(pDX, IDC_CLASS_REL_PARENT_EDIT, m_staticParent );
        DDX_Control(pDX, IDC_CLASS_REL_AUX_CLASSES, m_listboxAuxiliary);
        DDX_Control(pDX, IDC_CLASS_REL_SUPER_CLASSES, m_listboxSuperior);
    DDX_Text( pDX, IDC_CLASS_REL_NAME_STATIC, ObjectName );
    DDX_Text( pDX, IDC_CLASS_REL_PARENT_EDIT, ParentClass );
    DDX_Text( pDX, IDC_CLASS_REL_SYSCLASS_STATIC, SysClassString );
        //}}AFX_DATA_MAP


    if ( !pDX->m_bSaveAndValidate ) {

        //
        // Fill the auxiliary classes list box.
        //

                m_listboxAuxiliary.ResetContent();
        hr = InsertEditItems( m_listboxAuxiliary, strlistAuxiliary );
                ASSERT( SUCCEEDED(hr) );
        hr = InsertEditItems( m_listboxAuxiliary, strlistSystemAuxiliary );
                ASSERT( SUCCEEDED(hr) );

        //
        // Fill the possible superiors list box.
        //

                m_listboxSuperior.ResetContent();
        hr = InsertEditItems( m_listboxSuperior, strlistSuperior );
                ASSERT( SUCCEEDED(hr) );
        hr = InsertEditItems( m_listboxSuperior, strlistSystemSuperior );
                ASSERT( SUCCEEDED(hr) );

        m_listboxAuxiliary.OnSelChange();
        m_listboxSuperior.OnSelChange();

    } else {

        //
        // All changes that we save are tied to button control routines.
        //

                strlistAuxiliary.RemoveAll();
                hr = RetrieveEditItemsWithExclusions(
                        m_listboxAuxiliary,
                        strlistAuxiliary,
                        &strlistSystemAuxiliary
                        );
                ASSERT( SUCCEEDED(hr) );

                strlistSuperior.RemoveAll();
                hr = RetrieveEditItemsWithExclusions(
                        m_listboxSuperior,
                        strlistSuperior,
                        &strlistSystemSuperior
                        );
                ASSERT( SUCCEEDED(hr) );
    }
}

BEGIN_MESSAGE_MAP(ClassRelationshipPage, CPropertyPage)
        ON_BN_CLICKED(IDC_CLASS_REL_AUX_ADD,       OnButtonAuxiliaryClassAdd)
        ON_BN_CLICKED(IDC_CLASS_REL_AUX_REMOVE,    OnButtonAuxiliaryClassRemove)
        ON_BN_CLICKED(IDC_CLASS_REL_SUPER_ADD,     OnButtonSuperiorClassAdd)
        ON_BN_CLICKED(IDC_CLASS_REL_SUPER_REMOVE,  OnButtonSuperiorClassRemove)
        ON_LBN_SELCHANGE(IDC_CLASS_REL_AUX_CLASSES, OnAuxiliarySelChange)
        ON_LBN_SELCHANGE(IDC_CLASS_REL_SUPER_CLASSES, OnSuperiorSelChange)
        ON_MESSAGE(WM_HELP,                        OnHelp)
        ON_MESSAGE(WM_CONTEXTMENU,                 OnContextHelp)
END_MESSAGE_MAP()


BOOL
ClassRelationshipPage::OnApply(
)
//
// Revisions:
// CoryWest - 10/1/97 - Changes new additions to be listed by oid.
//                      Add cache freshening to improve performance.
//
{
    ASSERT( NULL != m_pIADsObject);

    HRESULT hr = S_OK;
    HRESULT flush_result;
    ListEntry *pNewList = NULL;
    BOOL fApplyAbort    = FALSE;  // stop later saves
    BOOL fApplyFailed   = FALSE;  // should not close the box

    if ( m_listboxAuxiliary.IsModified() )
    {
        //
        // Update the auxiliary classes
        //

        VARIANT AdsValue;
        VariantInit( &AdsValue );

        hr = StringListToVariant( AdsValue, strlistAuxiliary );
        ASSERT( SUCCEEDED(hr) );

        hr = m_pIADsObject->PutEx( ADS_PROPERTY_UPDATE, g_AuxiliaryClass, AdsValue );
        ASSERT( SUCCEEDED(hr)  );

        VariantClear( &AdsValue );

        hr = m_pIADsObject->SetInfo();

        if ( SUCCEEDED( hr )) {

            //
            // Update the aux class list in the cache.
            //

            hr = StringListToColumnList( m_pScopeControl,
                                         strlistAuxiliary,
                                         &pNewList );

            if ( SUCCEEDED( hr )) {

                m_pScopeControl->g_SchemaCache.FreeColumnList(
                    m_pSchemaObject->auxiliaryClass );
                m_pSchemaObject->auxiliaryClass = pNewList;

                //
                // Refresh the display!
                //

                m_pScopeControl->QueryConsole()->UpdateAllViews(
                    m_lpScopeDataObj, SCHMMGMT_CLASS, SCHMMGMT_UPDATEVIEW_REFRESH );
            }

            //
            // Continue with the directory operation even if
            // we couldn't update the display.
            //

            hr = S_OK;

        } else {

            //
            // Flush the IADS property cache so future
            // operations won't fail because of this one.
            //

            IADsPropertyList *pPropertyList;

            flush_result = m_pIADsObject->QueryInterface(
                             IID_IADsPropertyList,
                             reinterpret_cast<void**>(&pPropertyList) );

            if ( SUCCEEDED( flush_result ) ) {
                pPropertyList->PurgePropertyList();
                pPropertyList->Release();
            }
        }

    }

    if ( SUCCEEDED(hr) && m_listboxSuperior.IsModified() )
    {
        //
        // Update the superior classes
        //

        VARIANT AdsValue;
        VariantInit( &AdsValue );

        hr = StringListToVariant( AdsValue, strlistSuperior );
        ASSERT( SUCCEEDED(hr) );

        hr = m_pIADsObject->PutEx( ADS_PROPERTY_UPDATE, g_Superiors, AdsValue );
        ASSERT( SUCCEEDED(hr)  );
        VariantClear( &AdsValue );

        hr = m_pIADsObject->SetInfo();
    }

    if ( hr == ADS_EXTENDED_ERROR )
    {
        DoExtErrMsgBox();
    }
    else if ( FAILED(hr) )
    {
        if( ERROR_DS_UNWILLING_TO_PERFORM == HRESULT_CODE(hr) )
        {
            fApplyFailed = TRUE;
            DoErrMsgBox( ::GetActiveWindow(), TRUE, IDS_ERR_CHANGE_REJECT );
        }
        else
        {
            fApplyAbort = TRUE; 
            DoErrMsgBox( ::GetActiveWindow(), TRUE, GetErrorMessage(hr,TRUE) );
        }
    }
    else
    {

        // page is no longer "dirty"
        m_listboxAuxiliary.SetModified( FALSE );
        m_listboxSuperior.SetModified( FALSE );

		// Update comboBox status
		OnAuxiliarySelChange();
		OnSuperiorSelChange();
        
		SetModified( FALSE );
    }

    return !fApplyAbort && !fApplyFailed ;      // return TRUE if nothing happened
}



void ClassRelationshipPage::OnAuxiliarySelChange()
{
    m_listboxAuxiliary.OnSelChange();
}



void ClassRelationshipPage::OnSuperiorSelChange()
{
    m_listboxSuperior.OnSelChange();
}


void ClassRelationshipPage::OnButtonAuxiliaryClassRemove()
{
    if( m_listboxAuxiliary.RemoveListBoxItem() )
        SetModified( TRUE );
}


void ClassRelationshipPage::OnButtonSuperiorClassRemove()
{
    if( m_listboxSuperior.RemoveListBoxItem() )
        SetModified( TRUE );
}


void
ClassRelationshipPage::OnButtonAuxiliaryClassAdd()
{
    if( m_listboxAuxiliary.AddNewObjectToList() )
        SetModified( TRUE );
}


void
ClassRelationshipPage::OnButtonSuperiorClassAdd()
{
    if( m_listboxSuperior.AddNewObjectToList() )
        SetModified( TRUE );
}