// main.cxx -- top level construction routines
//
// Written by Curtis Olson, started March 1999.
//
// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)


#include <sys/types.h>  // for directory reading
#include <dirent.h>     // for directory reading

#include <Bucket/newbucket.hxx>

#include <Debug/logstream.hxx>
#include <Array/array.hxx>
#include <Clipper/clipper.hxx>
#include <GenOutput/genobj.hxx>
#include <Triangulate/triangle.hxx>


// load regular grid of elevation data (dem based), return list of
// fitted nodes
int load_dem(const string& work_base, FGBucket& b, FGArray& array) {
    fitnode_list result;
    string base = b.gen_base_path();

    string dem_path = work_base + ".dem" + "/Scenery/" + base 
	+ "/" + b.gen_index_str() + ".dem";
    cout << "dem_path = " << dem_path << endl;

    if ( ! array.open(dem_path) ) {
	cout << "ERROR: cannot open " << dem_path << endl;
	return 0;
    }

    array.parse();
    array.fit( 200 );

    return 1;
}


// do actual scan of directory and loading of files
int actual_load_polys( const string& dir, FGBucket& b, FGClipper& clipper ) {
    int counter = 0;
    string base = b.gen_base_path();
    string tile_str = b.gen_index_str();
    string ext;

    DIR *d;
    struct dirent *de;

    if ( (d = opendir( dir.c_str() )) == NULL ) {
        cout << "cannot open directory " << dir << "\n";
	return 0;
    }

    // load all matching polygon files
    string file, f_index, full_path;
    int pos;
    while ( (de = readdir(d)) != NULL ) {
	file = de->d_name;
	pos = file.find(".");
	f_index = file.substr(0, pos);

	if ( tile_str == f_index ) {
	    ext = file.substr(pos + 1);
	    cout << file << "  " << f_index << "  '" << ext << "'" << endl;
	    full_path = dir + "/" + file;
	    if ( (ext == "dem") || (ext == "dem.gz") ) {
		// skip
	    } else {
		cout << "ext = '" << ext << "'" << endl;
		clipper.load_polys( full_path );
		++counter;
	    }
	}
    }

    return counter;
}


// load all 2d polygons matching the specified base path and clip
// against each other to resolve any overlaps
int load_polys( const string& work_base, FGBucket& b, FGClipper& clipper) {
    string base = b.gen_base_path();
    int result;

    // initialize clipper
    clipper.init();

    // load airports
    string poly_path = work_base + ".apt" + "/Scenery/" + base;
    cout << "poly_path = " << poly_path << endl;
    result = actual_load_polys( poly_path, b, clipper );
    cout << "  loaded " << result << " polys" << endl;

    // load hydro
    poly_path = work_base + ".hydro" + "/Scenery/" + base;
    cout << "poly_path = " << poly_path << endl;
    result = actual_load_polys( poly_path, b, clipper );
    cout << "  loaded " << result << " polys" << endl;

    point2d min, max;
    min.x = b.get_center_lon() - 0.5 * b.get_width();
    min.y = b.get_center_lat() - 0.5 * b.get_height();
    max.x = b.get_center_lon() + 0.5 * b.get_width();
    max.y = b.get_center_lat() + 0.5 * b.get_height();

    // do clipping
    cout << "clipping polygons" << endl;
    clipper.clip_all(min, max);

    return 1;
}


// triangulate the data for each polygon
void do_triangulate( const FGArray& array, const FGClipper& clipper,
		  FGTriangle& t ) {
    // first we need to consolidate the points of the DEM fit list and
    // all the polygons into a more "Triangle" friendly format

    fitnode_list corner_list = array.get_corner_node_list();
    fitnode_list fit_list = array.get_fit_node_list();
    FGgpcPolyList gpc_polys = clipper.get_polys_clipped();

    cout << "ready to build node list and polygons" << endl;
    t.build( corner_list, fit_list, gpc_polys );
    cout << "done building node list and polygons" << endl;

    cout << "ready to do triangulation" << endl;
    t.run_triangulate();
    cout << "finished triangulation" << endl;
}


// generate the flight gear scenery file
void do_output( const string& base, const FGBucket &b, const FGTriangle& t, 
		const FGArray& array, FGGenOutput& output ) {
    output.build( array, t );
    output.write( base, b );
}


void construct_tile( const string& work_base, const string& output_base,
		     FGBucket& b )
{
    cout << "Construct tile, bucket = " << b << endl;

    // load and fit grid of elevation data
    FGArray array;
    load_dem( work_base, b, array );

    // load and clip 2d polygon data
    FGClipper clipper;
    load_polys( work_base, b, clipper );

    // triangulate the data for each polygon
    FGTriangle t;
    do_triangulate( array, clipper, t );

    // generate the output
    FGGenOutput output;
    do_output( output_base, b, t, array, output );
}


main(int argc, char **argv) {
    fitnode_list fit_list;
    double lon, lat;

    fglog().setLogLevels( FG_ALL, FG_DEBUG );

    if ( argc != 3 ) {
	cout << "Usage: " << argv[0] << " <work_base> <output_base>" << endl;
	exit(-1);
    }

    string work_base = argv[1];
    string output_base = argv[2];
   
    // lon = -146.248360; lat = 61.133950;     // PAVD (Valdez, AK)
    // lon = -110.664244; lat = 33.352890;     // P13
    // lon = -93.211389; lat = 45.145000;      // KANE
    // lon = -92.486188; lat = 44.590190;      // KRGK
    // lon = -89.744682312011719; lat= 29.314495086669922;
    // lon = -122.488090; lat = 42.743183;     // 64S
    // lon = -114.861097; lat = 35.947480;     // 61B
    lon = -112.012175; lat = 41.195944;      // KOGD

    double min_x = lon - 1;
    double min_y = lat - 1;
    FGBucket b_min( min_x, min_y );
    FGBucket b_max( lon + 1, lat + 1 );

    // FGBucket b(550363L);
    // construct_tile( work_base, output_base, b );
    // exit(0);

    if ( b_min == b_max ) {
	construct_tile( work_base, output_base, b_min );
    } else {
	FGBucket b_cur;
	int dx, dy, i, j;
	    
	fgBucketDiff(b_min, b_max, &dx, &dy);
	cout << "  construction area spans tile boundaries" << endl;
	cout << "  dx = " << dx << "  dy = " << dy << endl;

	for ( j = 0; j <= dy; j++ ) {
	    for ( i = 0; i <= dx; i++ ) {
		b_cur = fgBucketOffset(min_x, min_y, i, j);
		construct_tile( work_base, output_base, b_cur );
	    }
	}
	// string answer; cin >> answer;
    }
}


// $Log$
// Revision 1.10  1999/03/27 05:25:02  curt
// Fit with a value of 200 rather than 100.
// Handle corner nodes separately from the rest of the fitted nodes.
// Write scenery file to correct location.
// First hack at generating scenery for multiple tiles in one invocation.
//
// Revision 1.9  1999/03/25 19:04:31  curt
// Preparations for outputing scenery file to correct location.
// Minor tweaks related to FGBucket usage.
//
// Revision 1.8  1999/03/23 22:02:17  curt
// Worked on creating data to output ... normals, bounding spheres, etc.
//
// Revision 1.7  1999/03/22 23:48:29  curt
// Added GenOutput/
//
// Revision 1.6  1999/03/21 15:48:01  curt
// Removed Dem2node from the Tools fold.
// Tweaked the triangulator options to add quality mesh refinement.
//
// Revision 1.5  1999/03/21 14:02:05  curt
// Added a mechanism to dump out the triangle structures for viewing.
// Fixed a couple bugs in first pass at triangulation.
// - needed to explicitely initialize the polygon accumulator in triangle.cxx
//   before each polygon rather than depending on the default behavior.
// - Fixed a problem with region attribute propagation where I wasn't generating
//   the hole points correctly.
//
// Revision 1.4  1999/03/20 20:32:54  curt
// First mostly successful tile triangulation works.  There's plenty of tweaking
// to do, but we are marching in the right direction.
//
// Revision 1.3  1999/03/19 00:26:52  curt
// Minor tweaks ...
//
// Revision 1.2  1999/03/17 23:49:52  curt
// Started work on Triangulate/ section.
//
// Revision 1.1  1999/03/14 00:03:24  curt
// Initial revision.
//