/*
 * EncReader.h
 *
 *  Created on: Apr 5, 2011
 *      Author: godin
 */

#ifndef ENCREADER_H_
#define ENCREADER_H_

#include "logger/Logger.h"
#include "utils/FlexArray.h"

#include "../../Lib/opencpn/src/mygdal/ogr_s57.h"

struct EncScanPoints
{
public:
    EncScanPoints()
        : length_( 0 ),
          x_( NULL ),
          y_( NULL ),
          z_( NULL ),
          zz_( 0.0f )
    {}
    virtual ~EncScanPoints()
    {
        if( NULL != x_ ) delete[] x_;
        if( NULL != y_ ) delete[] y_;
        if( NULL != z_ ) delete[] z_;
    }
    int length_;
    int* x_;
    int* y_;
    int* z_;
    double zz_;
};

enum EncScanStep
{
    SCAN_SETUP,
    SCAN_FEATURES, // First pass through file, rcnm=100
    SCAN_FEATURES_DONE,
    SCAN_EDGES, // Second pass through file, rcnm=130
    SCAN_EDGES_DONE,
    SCAN_NODES, // Third pass through file, rcnm=110 & 120
    SCAN_NODES_DONE,
    SCAN_DONE
};

struct EncNode
{
public:
    EncNode()
        : id_( 0 ),
          x_( 0 ),
          y_( 0 )
    {}
    unsigned int id_;
    int x_;
    int y_;
};

struct EncEdge
{
public:
    EncEdge()
        : id_( 0 ),
          startNode_(),
          endNode_(),
          length_( 0 ),
          x_( NULL ),
          y_( NULL )
    {}
    ~EncEdge()
    {
        if( NULL != x_ ) delete[] x_;
        if( NULL != y_ ) delete[] y_;
    }
    unsigned int id_;
    EncNode startNode_;
    EncNode endNode_;
    int length_;
    int* x_;
    int* y_;
};

struct EncContour
{
public:
    EncContour()
        : depth_( 0.0f ),
          length_( 0 ),
          edgeCount_( 0 ),
          edges_( NULL )
    {}
    ~EncContour()
    {
        if( NULL != edges_ )
        {
            for( int i = 0; i < length_; ++i )
            {
                delete edges_[i];
            }
            delete[] edges_;
        }
    }
    float depth_;
    int length_;
    int edgeCount_;
    EncEdge** edges_;
};

struct EncArea
{
public:
    EncArea()
        : length_( 0 ),
          edgeCount_( 0 ),
          edges_( NULL ),
          reverses_( NULL ),
          segments_( 0 ),
          x0_( NULL ),
          y0_( NULL ),
          x1_( NULL ),
          y1_( NULL )
    {}
    ~EncArea()
    {
        if( NULL != edges_ )
        {
            for( int i =  0 ; i < length_; ++i )
            {
                delete edges_[i];
            }
            delete[] edges_;
        }
        if( NULL != reverses_ )
        {
            delete[] reverses_;
        }
        if( NULL != x0_ )
        {
            delete[] x0_;
            delete[] y0_;
            delete[] x1_;
            delete[] y1_;
        }
    }
    int length_;
    int edgeCount_;
    EncEdge** edges_;
    bool* reverses_;
    int segments_;
    float* x0_;
    float* y0_;
    float* x1_;
    float* y1_;

};

struct EncSounding
{
    unsigned int soundingId_;
};

class EncReader
{
public:

    EncReader( const char* filename );
    virtual ~EncReader();

    /// Returns false until scanning done.
    bool scan( EncScanPoints& points, Logger& logger );

    void uninitialize();

    bool scanDone()
    {
        return scanStep_ == SCAN_DONE;
    }

    EncArea* popCoverage();

private:

    // Note that the copy constructor below is private and not given a body.
    // Any attempt to call it will return a compiler error.
    EncReader( const EncReader& old ); // disallow copy constructor

    const Str filename_;


    FlexArray<EncContour*> contours_;
    FlexArray<EncArea*> coverages_;
    FlexArray<EncSounding*> soundings_;

    EncScanStep scanStep_;

    S57Reader* s57Reader_;

    DDFModule* ddfModule_;

    DDFRecord* record_;

    bool repeatRecord_;

    void populateEdge( EncEdge* edge, DDFRecord* record, const bool& reverse );

    void populateNode( EncNode& node, DDFRecord* record );

    void populatePoints( EncScanPoints& points, DDFRecord* record );

    void reduceNodes( EncContour* contour );

    void sortNodes( EncArea* area );

    void simplifyArea( EncArea* area );
};

#endif /* ENCREADER_H_ */
