/*
 * $Id: readps.cxx,v 4.5 2004/06/22 15:42:42 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-2004 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.
 * */

/*-----------------------------------------------------------------------
 * Utility function to help parse Postscript Files.
 *
 * Hugues Talbot	20 Jun 2004
 */

#include <string>
#include <iostream>
#include <fstream> // file streams
#include <sstream> // string stream

#include <stdio.h> // still needed for sscanf
#include <assert.h>

#include "imunistd.h"
#include "imview.hxx"
#include "machine.hxx"
#include "newprefio.hxx"
#include "readps.hxx"



using std::ifstream;
using std::ofstream;
using std::ostringstream;
using std::getline;
using std::string;
using std::exception;
using std::endl;
using std::ios_base;

extern imprefs *fileprefs;
extern float page_formats[][2];

// default constructor
psinfo::psinfo()
{
    init();
}

psinfo::psinfo(const char *fn)
{
    init();
    filename_ = fn;
    imtempnam(tmpfn_); // temporary file name (nothing is opened yet)
}

psinfo::~psinfo()
{
    dbgprintf("Deleting file %s\n", tmpfn_);
    unlink(tmpfn_); // delete the temporary file if it exists
}

void psinfo::init(void)
{
    Ox_ = Oy_ = 1e6; // outrageous number
    W_ = H_ = 0; // outrageous number
    filename_ = "";
    BBcs_ = "%%%%BoundingBox: %f %f %f %f";
    DocMedcs_ = "%%%%DocumentMedia: %*s %f %f";
    PgBBcs_ = "%%%%PageBoundingBox: %f %f %f %f";
    assert(fileprefs != 0);
    renderBB_ = fileprefs->psBoundingBox();
    assert((renderBB_ < PAGESIZE_NB) && (renderBB_ >= 0));
}

void psinfo::getBoundingBox(float &Ox, float &Oy, float &W, float &H)
{
    if (renderBB_ == PAGESIZE_AUTO) {
        Ox = Ox_ ; Oy = Oy_ ; W = W_; H = H_;
    } else {
        Ox = Oy = 0;
        W = page_formats[renderBB_][0];
        H = page_formats[renderBB_][1];
    }
    return;
}

// to incrementally find the right BB.
void psinfo::improveBB(float x1, float x2, float y1, float y2)
{
    float bbw, bbh;
    // found a bounding box
    if (x1 < Ox_)
	Ox_ = x1;
    if (y1 < Oy_)
	Oy_ = y1;
    bbw = x2 - x1;
    if (bbw > W_)
	W_ = bbw;
    bbh = y2 - y1;
    if (bbh > H_)
	H_ = bbh;

    return;
}

void psinfo::parsefile(void)
{
    dbgprintf("Parsing information from file %s\n", filename_);
    
    try {
	int nbscan = 0;
        bool hasShowpage = 0;
	ifstream PsFile(filename_);
        ofstream TmpFile(tmpfn_);
	if (PsFile) {
	    string            currentline;
            string            showpage("showpage");
	    string::size_type i;
	    float             bbx1=0, bbx2=0, bby1=0, bby2=0;
	    ostringstream     os_translate;
	    char              c;
	    unsigned int      cpl = showpage.length();

            // need to recenter to zero
            if (renderBB_ == PAGESIZE_AUTO) {
                dbgprintf("Leaving enough room for the final translation\n");
                TmpFile << bbx1 << " " << bby1 << " translate                  " << endl;
            }
                
	    //while (getline(PsFile, currentline)) {
	    currentline.erase();
	    while (PsFile.get(c)) {
		// this is to support Mac, PC and Unix terminations alike
		if ((c != '\n') && (c != '\r')) {
		    currentline.push_back(c);
		    continue;
		}
		    
		const char *pchline = currentline.c_str();
		// parsing for BoundingBox
		if ((nbscan = sscanf(pchline,BBcs_, &bbx1, &bby1, &bbx2, &bby2)) == 4) {
		    dbgprintf("Found bounding box %s\n", pchline);
		    improveBB(bbx1, bbx2, bby1, bby2);
		}
		// parsing for PageBoundingBox
		if ((nbscan = sscanf(pchline, PgBBcs_, &bbx1, &bby1, &bbx2, &bby2)) == 4) {
		    dbgprintf("Found page bounding box %s\n", pchline);
		    improveBB(bbx1, bbx2, bby1, bby2);
		}
		// parsing for DocumentMedia
		if ((nbscan = sscanf(pchline, DocMedcs_, &bbx2, &bby2)) == 2) {
		    dbgprintf("Found document media %s\n", pchline);
		    improveBB(Ox_, bbx2, Oy_, bby2);
		}
                if (!hasShowpage && ((i =currentline.find(showpage)) != string::npos)) {
		    if ((i==0) // start of line
			&& ((currentline.length() == cpl)  // End of line
			    || (currentline[cpl] == '\r') // Whitespace
			    || (currentline[cpl] == '\n') 
			    || (currentline[cpl] == '\t') 
			    || (currentline[cpl] == ' '))) {
			hasShowpage = true;
			dbgprintf("Found 'showpage' in file, line %s\n", pchline);
		    } else {
			dbgprintf("Found non-'showpage' ignored\n");
		    }
                }

                // copy the line
                TmpFile << currentline << endl;
		// empty the string and start again
		currentline.erase();
	    }
	    dbgprintf("PS file dimensions are:  (%f, %f), %f x %f\n", Ox_, Oy_, W_, H_);

            if (!hasShowpage) {
                // add a showpage at the end
                TmpFile << showpage << endl;
            }
	    if (renderBB_ == PAGESIZE_AUTO) {
		os_translate << -Ox_ << " " << -Oy_ << " translate";
		dbgprintf("going back to beginning and shifting the origin\n");
		TmpFile.seekp(0, ios_base::beg);
		TmpFile << os_translate.str() << endl;
		dbgprintf("Writing %s at the begining\n", os_translate.str().c_str());
	    }
	}

        // files are closed when destructed
    }
    catch (exception &e) {
	ostringstream osm;
	osm << "Error: " << e.what() ;
	warnprintf("Exception in psinfo::parsefile -> %s", osm.str().c_str());
	Ox_ = Oy_ = W_ = H_ = -1;
    }
    return;
}



