//////////////////////////////////////
// START of File: CE2_LINE.CPP
//////////////////////////////////////

//===================================================================
//
// COPYRIGHT NOTICE:  This code is protected by Copyright!
//
// Copyright (c) 1994, 1995, 1996, 1997 by DPC Technology.
// All rights reserved. 
//
// See files "cf_copyr.h" and "cf_licen.h" for details of 
// copyright and license specifications, and contact information.
//
//===================================================================

//
// Include this source file's header file:
// and any additional neccessary include statements.
//
#include	<cf_api/bf_defs.h>
#include    <cf_api/ce2_line.hpp> 

class       cf_XYZ;
class       cf_DataGroup;
#include    <cf_api/c1_dgrou.hpp>
            // We'll access the data groups/items in our Chart Model..

class       cf_3DPoint;
class       cf_3DPolyLine;
#include    <cf_api/co1_plin.hpp>
            // We'll add user data values into 2D/3D Line Series...

//--------------------------------
// Implement class cf_eng_Line2D:
//--------------------------------
cf_eng_Line2D::cf_eng_Line2D()

    :   cf_eng_CartXYZ( CF_TYPE_LINE, CF_DISP_2D )

{
    disp2D3DMode( CF_DISP_2D );   // Make it a 2D Chart!...

    // The BASE chart engine class will have instantiated
    // ALL the possible Grid/Tick Series to NULL...
    // The DERIVED chart engine classes MUST set
    // the series that they specifically want to be ON!...
    this->initGridTickSeries();
            // cf_engCartXYZ-derived charts can use either
            // the "default" XYZ/Cartesian method, which
            // activates the BOTTOM X-Axis as a "domain"
            // axis, and the LEFT Y-Axis as a "range over
            // chart model Y-Vals" axis, or define their
            // OWN version to over-ride the virtual XYZ/
            // Cartesian method...
}


cf_eng_Line2D::~cf_eng_Line2D()
{
}

void
cf_eng_Line2D::applyDataUpdate
                ( cf_ChartModel *p_cf_cmodlDataSource )
{
    // Reset the current data-state of the chart-engine:
    cf_ChartEngine::applyDataUpdate( p_cf_cmodlDataSource );
                    // ...by using the base-class shared-functionality..

    // Now -- Generate a set of "new" Chart Engine Objects:
    cf_IndexMode enumCurrIndexMode = p_cf_cmodlDataSource->dataIndexMethod();

    // We will generate "Virtual 2D Line Points and PolyLines"
    // for each of the Chart's Data Items with these vars:
    cf_DataGroup        *p_cf_dgAccessGroup;
    cf_XYZ              *p_cf_xyzAccessItem;
                        // We'll point along the various groups/items

    cf_3DPoint          cf_3dpNewPoint;
    double              dXVal, dYVal, dZVal;
                        // and grab X/Y-vals to add as points to the...

    cf_3DPolyLine       *p_cf_3dplNewSeries;
                        // ...series which represent the data groups...

    // We will iterate over the available groups and generate
    // 2D PolyLines from the data elements in the parent
    // cf_ChartModel's data groups:
    int iStartAt = p_cf_cmodlDataSource->dataGroupsStartAt();
    int iEndAt = p_cf_cmodlDataSource->dataGroupsEndAt();

    // Compute the max number of axis items to iterate over:
    int iNumActiveInGroup = 0;
    int iNumDomainAxisItems = 0;
    for ( i = iStartAt; i <= iEndAt; i++ )
    {
        p_cf_dgAccessGroup = p_cf_cmodlDataSource->activateGroupUserData( i );
        iNumActiveInGroup = p_cf_dgAccessGroup->numItems();
        if ( iNumActiveInGroup > iNumDomainAxisItems )
                iNumDomainAxisItems = iNumActiveInGroup;
    }           // We now have our iteration limit...


    // Begin a for-loop over the active group range:
    for ( i = iStartAt; i <= iEndAt; i++ )
    {
        // Activate each chart group, and get a pointer to it:
        p_cf_dgAccessGroup = p_cf_cmodlDataSource->activateGroupUserData( i );

        // Only add a virtual chart object IF there is data to use:
        if ( p_cf_dgAccessGroup->hasData() )
        {
            // Define a new 2D/3D poly-line...
            p_cf_3dplNewSeries = new cf_3DPolyLine( p_cf_dgAccessGroup->dispAttribs() );

            // ...with the Z-Depth dependent on the index-mode:
            if ( enumCurrIndexMode == CF_INDEX_USR_X )
                dZVal = p_cf_dgAccessGroup->dataZMin();
            else
                dZVal = ( i - 1 );

            // Now we'll add data-points:
            iNumActiveInGroup = p_cf_dgAccessGroup->numItems();
            for ( j = 1; j <= iNumActiveInGroup; j++ )
            {
                // An XY pair at a Z-Depth will define a new PolyLine point...
                p_cf_xyzAccessItem = p_cf_dgAccessGroup->activateXYZValAt( j );

                // The X-Value is defined by the Index-Mode!
                if ( enumCurrIndexMode == CF_INDEX_USR_X )
                    dXVal = p_cf_xyzAccessItem->x();
                else if ( enumCurrIndexMode == CF_INDEX_INT_I )
                    dXVal = ( j - 1 );
                else
                    dXVal = j;

                // The Y-Value is simply the data-point:
                dYVal = p_cf_xyzAccessItem->y();

                cf_3dpNewPoint.dataXYZ( dXVal, dYVal, dZVal );
                p_cf_3dplNewSeries->addPoint( cf_3dpNewPoint );

            }   // end of for-loop over iNumCurrentItems

            // Add the group/series to the engine...
            this->addSpaceObject( p_cf_3dplNewSeries );

        }   // end of if-then screen for actual group data

    }   // end of for-loop over Data Groups

    // Finish-up by:
    updateAxisGridTickSeries( p_cf_cmodlDataSource );
        // ...generating domain and range axis grid/tick/series objects:
    updateAxisRangeBufferPoints( p_cf_cmodlDataSource );
        // ...generating range axis buffering (by adding "invisible" 3D-points):

}   // end of cf_eng_Line2D::applyDataUpdate(...)

//
// END of class cf_eng_Line2D Implementation
//
    
//////////////////////////////////////
// END of File: CE2_LINE.CPP
//////////////////////////////////////

