/*
** MUDoc_Embed.c
**
** Auxiliary functions for MUDoc.c
**
** Oct2020 - ABU fecit
*/

#include <string.h>
#include "xpdf_extension.h"
#include "MUDoc_Embed.h"


	// transform the coords of a fz_point, expressed in 'windows coord-sys' (fitz page space)
	//  i.e relative to the absoluteBox (i.e a /CropBox )
	// to PDF user space coord sys
static 
fz_point _PDF_point (fz_rect absBox, fz_point p) {
	p.x += absBox.x0;
	p.y = absBox.y1 - p.y ;
	return p;
}

	// transform the coords of a fz_rect, expressed in 'windows coord-sys' (fitz page space)
	//  i.e relative to the absoluteBox (i.e a /CropBox )
	// to PDF user space coord sys
static 
fz_rect _PDF_rect (fz_rect absBox, fz_rect r) {
	r.x0 += absBox.x0;
	r.x1 += absBox.x0;
	float RY0 = r.y0;   // tmp save
	r.y0 = absBox.y1 - r.y1 ;
	r.y1 = absBox.y1 - RY0;
	return r;
}


TclResCode mu_embed_xobj(Tcl_Interp* interp,
	fz_context* ctx,
	pdf_document* doc,
	pdf_page *toPage,   // where to embed xobj
	pdf_obj *xobj,
	struct embedParams *param
	) {
	
	fz_var(toPage);
	fz_try( ctx ) {

		 // from param->anchor, compute anchor-point ap
		fz_point ap;
		if ( strchr( param->anchor, 's' ) ) {
			ap.y = param->crop.y1;
		} else if ( strchr( param->anchor, 'n') ) {
			ap.y = param->crop.y0;
		} else {
			ap.y = (param->crop.y0+param->crop.y1)/2;
		}
		if ( strchr( param->anchor, 'w' ) ) {
			ap.x = param->crop.x0;
		} else if ( strchr( param->anchor, 'e') ) {
			ap.x = param->crop.x1;
		} else {
			ap.x = (param->crop.x0+param->crop.x1)/2;
		}

		 // now transform from fitz coord-sys to PDF coords-sys
		ap = _PDF_point(pdf_xobject_bbox(ctx, xobj), ap);
		fz_point to = _PDF_point(xpdf_page_cropbox(ctx, toPage), param->to);
		fz_rect  newRect = _PDF_rect(pdf_xobject_bbox(ctx, xobj), param->crop);

		fz_matrix mtx;
		mtx = fz_translate(-ap.x, -ap.y);
		mtx = fz_concat( mtx, fz_scale( param->zoom, param->zoom ));
		mtx = fz_concat( mtx, fz_rotate(param->angle)) ;
		 // collimate ap to to.xy
		mtx = fz_concat( mtx , fz_translate(to.x,to.y) );

		xpdf_xobject_embed(ctx, doc, toPage, xobj, mtx, newRect, param->over);
	} fz_catch( ctx ) {
		Tcl_SetObjResult(interp, Tcl_NewStringObj(fz_caught_message(ctx),-1));
		return TCL_ERROR;  	
	}
	return TCL_OK;
}


  // Parse the optional parameters of the embedPage cmd.
  // Store values in struct embedParam.
  // On error return TCL_ERROR ; an error message is left in the interpreter's result
int _parseEmbedPageOptions( Tcl_Interp *interp, int objc, Tcl_Obj* const objv[], struct embedParams *param ) {
	int argIdx = 0;
	while (argIdx < objc) {
		char *arg = Tcl_GetString(objv[argIdx++]);
		
		if ( argIdx >= objc ) {
			Tcl_SetObjResult(interp, Tcl_ObjPrintf( "option \"%s\" requires a value", arg));
			return TCL_ERROR;
		}
		
		// ? -crop
		if( strcmp(arg,"-crop") == 0 ) {
			// The fz_rect is an array of 4 floats
			if( xTcl_Get_N_Floats_FromObj( interp, objv[argIdx], 4, (float*)&(param->crop) ) != TCL_OK ) {
				return TCL_ERROR;
			}
			// result's analysis will be performed later ..
		// ? -anchor
		} else if (strcmp(arg,"-anchor") == 0 ) {
			// anchor is a string of 2 chars max
			const char* validAnchors[] = {
				"c", "n", "s", "w", "e", "nw", "ne", "sw", "se", NULL
			};
			const char* anchorValue = Tcl_GetString(objv[argIdx]);
			const char** p = validAnchors;
			while (*p && strcmp(*p,anchorValue)!=0) {
				++p;
			}
			if ( !*p  ) {
				Tcl_SetObjResult(interp,Tcl_ObjPrintf("\"%s\" option requires c,n,s,w,,e,ne,nw,se,sw.",arg));
				return TCL_ERROR;
			}
			strncpy(param->anchor, anchorValue, 3);
		// ? -to
		} else if (strcmp(arg,"-to") == 0 ) {
			// The fz_point is an array of 2 floats
			if( xTcl_Get_N_Floats_FromObj( interp, objv[argIdx], 2, (float*)&(param->to) ) != TCL_OK ) {
				return TCL_ERROR;
			}
			param->has_to = 1;
			// result's analysis will be performed later ..
			
		// -scale
		} else if (strcmp(arg,"-scale") == 0 ) {
			double doubleVal;
			if ( Tcl_GetDoubleFromObj(NULL, objv[argIdx], &doubleVal) != TCL_OK  ||  doubleVal < 1E-6 ) {
				Tcl_SetObjResult(interp, Tcl_ObjPrintf( "option \"%s\" requires a positive value greater than 0.000001", arg));
				return TCL_ERROR;
			}
			param->zoom = doubleVal;
			
		// -rotate
		} else if (strcmp(arg,"-rotate") == 0 ) {
			double doubleVal;
			if ( Tcl_GetDoubleFromObj(NULL, objv[argIdx], &doubleVal) != TCL_OK ) {
				Tcl_SetObjResult(interp, Tcl_ObjPrintf( "option \"%s\" requires a numeric value", arg));
				return TCL_ERROR;
			}
			param->angle = doubleVal;
			
		// -over
		} else if (strcmp(arg,"-over") == 0 ) {
			int boolVal;
			if ( Tcl_GetBooleanFromObj(NULL, objv[argIdx], &boolVal) != TCL_OK) {
				return TCL_ERROR;
			}
			param->over = boolVal;
			
		// ? else ?
		} else {
			Tcl_SetObjResult(interp, Tcl_ObjPrintf( "unrecognized option \"%s\". Valid options are: -crop,-to,-scale,-rotate,-over", arg));
			return TCL_ERROR;
		}
		++argIdx;
	}
	return TCL_OK;
}
