/*
 * $Id: pointfile.hxx,v 4.4 2004/06/23 15:58:17 hut66au Exp $
 *
 * Imview, the portable image analysis application
 * http://www.cmis.csiro.au/Hugues.Talbot/imview
 * ----------------------------------------------------------
 *
 *  Imview is an attempt to provide an image display application
 *  suitable for professional image analysis. It was started in
 *  1997 and is mostly the result of the efforts of Hugues Talbot,
 *  Image Analysis Project, CSIRO Mathematical and Information
 *  Sciences, with help from others (see the CREDITS files for
 *  more information)
 *
 *  Imview is Copyrighted (C) 1997-2001 by Hugues Talbot and was
 *  supported in parts by the Australian Commonwealth Science and 
 *  Industry Research Organisation. Please see the COPYRIGHT file 
 *  for full details. Imview also includes the contributions of 
 *  many others. Please see the CREDITS file for full details.
 *
 *  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., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
 * */

/*------------------------------------------------------------------------
 *
 * the pointfile class
 *
 * This class is responsible for handling pointfiles, and is
 * a cheap excuse to learn more about C++ streams, strings, and
 * the STL in general.
 *
 * Hugues Talbot	 4 Mar 1998
 *      
 *-----------------------------------------------------------------------*/

#ifndef POINTFILE_H
#define POINTFILE_H

#include <stdio.h>
#include <stdlib.h>
#include <errno.h> 
#include <math.h>

#include <fstream>
#include <sstream> // string stream
#include <iomanip>
#include <string>
#include <list>

#include <FL/Fl_Object.H>
#include <FL/Fl_Group.H>
#include <FL/fl_draw.H>

#include "imnmspc.hxx" // namespace def. if required

#include "imlines.hxx"

using std::ostream;
using std::ofstream;
using std::ifstream;
using std::endl;
using std::setw;
using std::list;
using std::string;
using std::ostringstream;

#define  PTFILE_CUTOFFD  5  // distance cut-off in pixels

#define  STR_LINE_LN     7  // line between point and text, if any

#define  WEIRD_CONSTANT  -1234321 // to indicate a `break'

extern string ptDummyStr; // serves no purpose other than enabling default string argument

typedef enum {
    PT_SELECT_ADD = 0,
    PT_SELECT_RM,
    PT_SELECT_INVERT,
    PT_SELECT_ALL,
    PT_SELECT_NONE,
} ptselectflag;

// helper class
// weird collection of parameters
struct pointParams {
    pointParams(void) {
	annotated = false;
	txt=ptDummyStr;
	col = FL_BLACK;
	font = 0;
	size = 0;
	length = 0;
	qdr = STR_NE;
	h = false;
	pts = 3;
        lsty = STYLE_FILLED_BW;
        lcol = FL_WHITE;
    }
    bool annotated;
    string txt; // text that goes with the point
    Fl_Color col;  // color of the point and text
    int font; // font of the text
    int size; // size of the font
    int length; // length of the line
    str_quadrant qdr; // direction of line from point
    bool h; // hidden or not
    int pts; // point size.
    linestyle lsty; // style of the linework -- only for breaks
    Fl_Color lcol; // colour of the linework -- only for breaks
};

// this class will grow in time...
class mypoint: public Fl_Object {
public:
    mypoint(void);
    mypoint(const mypoint& p);
    mypoint(int X, int Y, int Z,
	    unsigned char Rval, unsigned char Gval, unsigned char Bval,
	    int nbraw, bool annotated=false, string &txt = ptDummyStr , Fl_Color col = FL_BLACK, int font = 0,
	    int size = 0, int length = 0, str_quadrant qdr = STR_NE, bool h = false,
	    int pts = 3, linestyle lsty = STYLE_FILLED_BW, Fl_Color lcol = FL_WHITE) ;
    mypoint& operator=(mypoint &p);
    ~mypoint();
    int x() const { return x_;}
    int y() const { return y_;}
    int z() const { return z_;}
    int Rval() const { return Rval_;}
    int Gval() const { return Gval_;}
    int Bval() const { return Bval_;}
    int nbraw() const {return nbraw_;}
    int radius() const {return radius_;}
    void radius(int v) {radius_ = v;}
    const string& annotation() const {return annotation_;}
    const string& annotation_inlined(void);
    void annotation(string &in) {annotation_ = in;}
    void annotation_inlined(string &in);
    Fl_Color stringColour() const {return stringColour_;}
    void stringColour(Fl_Color c) {stringColour_ = c;}
    int stringFont() const {return stringFont_;}
    void stringFont(int f) {stringFont_ = f;}
    int stringSize() const {return stringSize_;}
    void stringSize(int s) {stringSize_ = s;}
    str_quadrant stringQuadrant() const {return stringQuadrant_;}
    void stringQuadrant(str_quadrant q) {stringQuadrant_ = q;}
    void linelength(int l) {linelength_ = l;}
    int linelength(void) const {return linelength_;}
    void pointdefaults(const pointParams &pp);
    void draw();
    void select(bool value = true) {selected_=value;}
    bool selected(void) const {return selected_;}
    bool isBreak(void) const {return (z_ == WEIRD_CONSTANT);}
    bool hasAnnotation(void) const {return hasAnnotation_;}
    bool isHidden(void) const {return hidden_;}
    void hide(bool v) {hidden_ = v;}
    linestyle getLSty(void) const {return lsty_;}
    Fl_Color getLCol(void) const {return lcol_;}
    // point rotation
    void rotate90p(void);
    void rotate90m(void);
    void rotate3dup(void);
    void rotate3ddown(void);
    void flipv(void);
    void fliph(void);
    // selection predicate
    bool            isSelectedPred(void);
    void            removeself(Fl_Group* v) {if (!isBreak()) v->remove(*this);} // remove self from list of things to draw
    void            addself(Fl_Group* v) {if (!isBreak()) v->add(*this);} // add self to list of things to draw
    
private:
    int           x_, y_, z_;
    unsigned char Rval_, Gval_, Bval_;
    int           nbraw_;
    int           radius_;
    string        annotation_, annotation_inlined_;
    Fl_Color      stringColour_, lcol_;
    int           stringFont_, stringSize_, linelength_;
    str_quadrant  stringQuadrant_;
    bool          selected_, hidden_, hasAnnotation_;
    linestyle      lsty_;
    pointParams    defaultParms_;
};

// quick, define a list iterator!
typedef list<mypoint>::iterator           pointIterator;
typedef list<mypoint>::reverse_iterator   pointRIterator;
typedef list<imline>::iterator            lineIterator;
typedef list<imline>::reverse_iterator    lineRIterator;

class pointfile {
private:
    int          outputlist(ostream &sout); // output the pf to an arbitrary stream
    pointIterator findClosestPoint(int x, int y);
    bool         isValid(pointIterator i) {return(i != pointlist.end());}
    void         changeSelection(int x, int y, int w, int h, bool selectStatus);
 
public:
    pointfile();
    ~pointfile();
    
    int addPoint(int x, int y, int z,
		 unsigned char Rval,
		 unsigned char Gval,
		 unsigned char Bval,
		 int           hasRaw,
		 bool          hasAnnotation = false,
		 string        &annotation = ptDummyStr,
		 Fl_Color       color=FL_RED,
		 int            font=0,
		 int            size=0,
		 int            length=0,
		 str_quadrant   qdr=STR_NE,
		 bool           hidden = false,
		 int            ptsize = 3,
		 linestyle      lstyle = STYLE_FILLED_BW,
		 Fl_Color       lcolour= FL_WHITE);

    // same as above, slightly more convenient.
    int addPoint(int x, int y, int z,
		 unsigned char Rval,
		 unsigned char Gval,
		 unsigned char Bval,
		 int           hasRaw,
		 pointParams &pp);
    

    void         addBreak(bool redraw = true, linestyle lsty=STYLE_FILLED_BW, Fl_Color lcol=FL_WHITE);
    void         redrawLines(void);
    void         resetLinesStatus(void);
    void         imageName(const char *p) {imgName = p;}
    void         rmPoint(int x, int y);
    void         annotatePoint(int x, int y);
    int          getNearestPointParameters(int X, int Y, string &ann, Fl_Color &col,
					   int &font, int &size, int &length,
					   str_quadrant &q, bool &hidden, int &pointsize);
    bool         isValidPoint(int x, int y) {return isValid(findClosestPoint(x,y));}
    void         rmLastPoint(void);
    void         rmAllPoints(void);
    bool         rmSelectedPoints(void);
    void         rmPointGroup(int x, int y);
    void         selectPoints(int x, int y, int w, int h, ptselectflag flag=PT_SELECT_ADD);
    void         showlist(void);
    int          savelist(bool forsure=true); // to the pointfile
    int          savelist(string &s); // to an arbitrary string
    void         readlist(void);
    void         getlist(string &s);
    int          nbPointsInList(void);
    int          nbBreaksInList(void);
    void         xorValueForLines(int x) {xorvalforlines = x;}
    int          xorValueForLines(void) {return xorvalforlines;}
    void         setCurrentLineStyle(linestyle l) {currentlinestyle_ = l;}
    void         setCurrentLineColour(Fl_Color c) {currentlinecolour_ = c;}
    // provide access to the point file name.
    int          setPtFileName(const char *nm);
    const char  *getPtFileName(void);
    const char  *getPtFileNameIfPresent(const char *imageName);
    // points transformation
    void         rotate90p(void);
    void         rotate90m(void);
    void         rotate3dup(void);
    void         rotate3ddown(void);
    void         flipv(void);
    void         fliph(void);

private:
    
    int             saveAsOldFormat;
    int             xorvalforlines;
    bool            hasChanged;
    string          PtFileName;
    string          imgName;
    list <mypoint>  pointlist;
    list <imline>   linelist;
    linestyle       currentlinestyle_;
    Fl_Color        currentlinecolour_;
    
};

#endif // POINTFILE
