/** \file trkseg.h
 *
 */

/*  XTrkCad - Model Railroad CAD
 *  Copyright (C) 2005 Dave Bullis
 *
 *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#ifndef TRKSEG_H
#define TRKSEG_H

#include "common.h"

#define MAX_PATH_SEGS	(127)

typedef enum { FREEFORM, RECTANGLE, POLYLINE
             } PolyType_e;


typedef struct trkSeg_t {
	char type;
	wDrawColor color;
	LWIDTH_T lineWidth;
	dynArr_t bezSegs;       //placed here to avoid overwrites
	union {
		struct {
			coOrd pos[4];
			ANGLE_T angle;
			long option;
		} l;
		struct {
			coOrd pos[4];
			ANGLE_T angle0;
			ANGLE_T angle3;
			DIST_T minRadius;
			DIST_T radius0;
			DIST_T radius3;
			DIST_T length;
		} b;
		struct {
			coOrd center;
			ANGLE_T a0, a1;
			DIST_T radius;
		} c;
		struct {
			coOrd pos;
			ANGLE_T angle;
			DIST_T R, L;
			DIST_T l0, l1;
			unsigned int flip:1;
			unsigned int negate:1;
			unsigned int Scurve:1;
		} j;
		struct {
			coOrd pos;
			ANGLE_T angle;
			wFont_p fontP;
			FONTSIZE_T fontSize;
			BOOL_T boxed;
			char * string;
		} t;
		struct {
			int cnt;
			pts_t * pts;
			coOrd orig;
			ANGLE_T angle;
			PolyType_e polyType;
		} p;
	} u;
} trkSeg_t;
typedef struct trkSeg_t * trkSeg_p;

#define SEG_STRTRK		('S')
#define SEG_CRVTRK		('C')
#define SEG_BEZTRK      ('W')
#define SEG_STRLIN		('L')
#define SEG_CRVLIN		('A')
#define SEG_BEZLIN      ('H')
#define SEG_JNTTRK		('J')
#define SEG_FILCRCL		('G')
#define SEG_POLY		('Y')
#define SEG_FILPOLY		('F')
#define SEG_TEXT		('Z')
#define SEG_UNCEP		('E')
#define SEG_CONEP		('T')
#define SEG_PATH		('P')
#define SEG_SPEC		('X')
#define SEG_CUST		('U')
#define SEG_DOFF		('D')
#define SEG_BENCH		('B')
#define SEG_DIMLIN		('M')
#define SEG_TBLEDGE		('Q')

#define IsSegTrack( S ) ( (S)->type == SEG_STRTRK || (S)->type == SEG_CRVTRK || (S)->type == SEG_JNTTRK || (S)->type == SEG_BEZTRK)

extern dynArr_t tempSegs_da;

#define tempSegs(N) DYNARR_N( trkSeg_t, tempSegs_da, N )

extern char tempSpecial[4096];
extern char tempCustom[4096];

void ComputeCurvedSeg(
        trkSeg_p s,
        DIST_T radius,
        coOrd p0,
        coOrd p1 );

coOrd GetSegEndPt(
        trkSeg_p segPtr,
        EPINX_T ep,
        BOOL_T bounds,
        ANGLE_T * );

void GetTextBounds( coOrd, ANGLE_T, char *, FONTSIZE_T, coOrd *, coOrd * );
void GetSegBounds( coOrd, ANGLE_T, wIndex_t, trkSeg_p, coOrd *, coOrd * );
void MoveSegs( wIndex_t, trkSeg_p, coOrd );
void RotateSegs( wIndex_t, trkSeg_p, coOrd, ANGLE_T );
void FlipSegs( wIndex_t, trkSeg_p, coOrd, ANGLE_T );
void RescaleSegs( wIndex_t, trkSeg_p, DIST_T, DIST_T, DIST_T );
void CloneFilledDraw( wIndex_t, trkSeg_p, BOOL_T );
void FreeFilledDraw( wIndex_t, trkSeg_p );
DIST_T DistanceSegs( coOrd, ANGLE_T, wIndex_t, trkSeg_p, coOrd *, wIndex_t * );
ANGLE_T GetAngleSegs( wIndex_t, trkSeg_p, coOrd *, wIndex_t *, DIST_T *,
                      BOOL_T *, wIndex_t *, BOOL_T * );
void RecolorSegs( wIndex_t, trkSeg_p, wDrawColor );
BOOL_T ReadSegs( void );
BOOL_T WriteSegs( FILE * f, wIndex_t segCnt, trkSeg_p segs );
BOOL_T WriteSegsEnd(FILE * f, wIndex_t segCnt, trkSeg_p segs, BOOL_T writeEnd);


typedef union {
	struct {
		coOrd pos;				/* IN the point to get to */
		ANGLE_T angle;			/* IN  is the angle that the object starts at (-ve for forwards) */
		DIST_T dist;			/* OUT is how far it is along the track to get to pos*/
		BOOL_T backwards;		/* OUT which way are we going? */
		BOOL_T reverse_seg;		/* OUT the seg is backwards curve */
		BOOL_T negative;		/* OUT the curve is negative */
		int BezSegInx;			/* OUT for Bezier Seg - the segment we are on in Bezier */
		BOOL_T segs_backwards;  /* OUT for Bezier Seg - the direction of the overall Bezier */
	} traverse1;				// Find dist between pos and end of track that starts with angle set backwards
	struct {
		BOOL_T segDir;			/* IN Direction to go in this seg*/
		int BezSegInx;			/* IN for Bezier Seg which element to start with*/
		BOOL_T segs_backwards;  /* IN for Bezier Seg  which way to go down the array*/
		DIST_T dist;			/* IN/OUT In = distance to go, Out = distance left */
		coOrd pos;				/* OUT = point reached if dist = 0 */
		ANGLE_T angle;			/* OUT = angle at point */
	} traverse2;			//Return distance left (or 0) and angle and pos when going dist from segDir end
	struct {
		int first, last;		/* IN */
		ANGLE_T side;
		DIST_T roadbedWidth;
		wDrawWidth rbw;
		coOrd orig;
		ANGLE_T angle;
		wDrawColor color;
		drawCmd_p d;
	} drawRoadbedSide;
	struct {
		coOrd pos1;				/* IN pos to find */
		DIST_T dd;				/* OUT distance from nearest point in seg to input pos */
	} distance;
	struct {
		track_p trk;			/* OUT */
		EPINX_T ep[2];
	} newTrack;
	struct {
		DIST_T length;			/* OUT */
	} length;
	struct {
		coOrd pos;				/* IN */
		DIST_T length[2];		/* OUT */
		trkSeg_t newSeg[2];
	} split;
	struct {
		coOrd pos;				/* IN Pos to find nearest to  - OUT found pos on curve*/
		ANGLE_T angle;			/* OUT angle at pos - (-ve if backwards)*/
		BOOL_T negative_radius; /* OUT Radius <0? */
		BOOL_T backwards;		/* OUT Seg is backwards */
		DIST_T radius;			/* OUT radius at pos */
		coOrd center;			/* OUT center of curvature at pos (0 = straight)*/
		int  bezSegInx;			/* OUT if a bezier proc, the index of the sub segment */
	} getAngle;			// Get pos on seg nearest, angle at that (-ve for forwards)
} segProcData_t, *segProcData_p;
typedef enum {
	SEGPROC_TRAVERSE1,
	SEGPROC_TRAVERSE2,
	SEGPROC_DRAWROADBEDSIDE,
	SEGPROC_DISTANCE,
	SEGPROC_FLIP,
	SEGPROC_NEWTRACK,
	SEGPROC_LENGTH,
	SEGPROC_SPLIT,
	SEGPROC_GETANGLE
} segProc_e;

void SegProc( segProc_e, trkSeg_p, segProcData_p );
void DrawDimLine( drawCmd_p, coOrd, coOrd, char *, wFontSize_t, FLOAT_T,
                  wDrawWidth, wDrawColor, long );
void DrawSegs(
        drawCmd_p d,
        coOrd orig,
        ANGLE_T angle,
        trkSeg_p segPtr,
        wIndex_t segCnt,
        DIST_T trackGauge,
        wDrawColor color );
void DrawSegsDA(
        drawCmd_p d,
        track_p trk,
        coOrd orig,
        ANGLE_T angle,
        dynArr_t * da,
        DIST_T trackGauge,
        wDrawColor color,
        long options );
void DrawSegsO(
        drawCmd_p d,
        track_p trk,
        coOrd orig,
        ANGLE_T angle,
        trkSeg_p segPtr,
        wIndex_t segCnt,
        DIST_T trackGauge,
        wDrawColor color,
        long options );


void StraightSegProc( segProc_e, trkSeg_p, segProcData_p );
void CurveSegProc( segProc_e, trkSeg_p, segProcData_p );
void JointSegProc( segProc_e, trkSeg_p, segProcData_p );
void BezierSegProc( segProc_e, trkSeg_p, segProcData_p );   //Used in Cornu join
void CleanSegs( dynArr_t *);
void CopyPoly(trkSeg_p seg_p, wIndex_t segCnt);
wBool_t CompareSegs( trkSeg_p, int, trkSeg_p, int );
#endif
