// Copyright 1998 Acorn Computers Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "kernel.h"
#include "drawfile.h"
#include "walkth.h"
#include "tboxclass.h"

extern PalTask abc_task;

void
drawfile::set_A4_extent_with_zoom()
{
  if (ratio[1] == 0) ratio[1] = 1;	// not doing a division by 0

  w_extent.xmin = 0;
  w_extent.xmax = (int)((ratio[0]/(float)ratio[1]) * 210 * MM_OSUNIT); // os units
  w_extent.ymin = 0;
  w_extent.ymax = (int)((ratio[0]/(float)ratio[1]) * 297 * MM_OSUNIT); // os units
}

int
drawfile::file_size(char *s_filename)
{
  _kernel_swi_regs regs;
  regs.r[0] = 17;
  regs.r[1] = (int) s_filename;

  Error(_kernel_swi(OS_File,&regs,&regs)) ;

  return regs.r[4];
}

void
drawfile::file_load(char *s_filename)
{
  if (allocated_file == NULL){
  	Error(error_construct("Err_Memory"));
  	return;
  }

  _kernel_swi_regs regs;
  regs.r[0] = 16;
  regs.r[1] = (int) s_filename;
  regs.r[2] = (int) allocated_file;
  regs.r[3] = 0;

  Error(_kernel_swi(OS_File,&regs,&regs));
}

drawfile::drawfile()
{
  ComponentId comp_id;
  ObjectId parent, toolbar_id = 0;
  int temp_extent;

  Error( Window::Create(0,"Window") );	// does the attach

  Error( GetToolBars( 0x01, &toolbar_id, NULL, NULL, NULL) );

  if (toolbar_id != 0) toolbar.Attach(toolbar_id);
  else
     BadError(error_construct("Err_Obj"));

  allocated_file = NULL;
  load_new_file(toolbar.stages[toolbar.stage_count].file_name);

  ratio[0] = 1;
  ratio[1] = 1;

  set_A4_extent_with_zoom();
  Error( SetExtent(0, &w_extent) );
  temp_extent = w_extent.ymax;
  w_extent.ymax = 100;
  Error( toolbar.SetExtent(0, &w_extent) ); 	// this can be overwritten in a smaller screen
  w_extent.ymax = temp_extent;			// mode so this insures the size

  comp_id = 0;
  Error( GetParent(0, &parent, &comp_id) );
  Error( Show( 0, 0, NULL, parent, comp_id ) );
}

drawfile::~drawfile()
{
  delete allocated_file;
  abc_task.recorded_message_list.DeRegisterWaitingForMessage(mOID);
}

void
drawfile::MessageHandler(WimpMessage *message)
{
 _kernel_swi_regs regs;		//PrintSave request
  //TRACE("Received a message %i", message->hdr.action_code);

  abc_task.recorded_message_list.DeRegisterWaitingForMessage(mOID, Wimp_MPrintTypeOdd);
  abc_task.recorded_message_list.DeRegisterWaitingForMessage(mOID, Wimp_MPrintError);

  //TRACE("De register");

  if (message->hdr.action_code == Wimp_MPrintError){
  	Error(error_construct("Err_Print"));
  	return;
  }

  message->hdr.your_ref = message->hdr.my_ref;
  message->hdr.action_code = Wimp_MPrintTypeKnown;

  regs.r[0] = Wimp_EUserMessage;  		//code user recorded or Acknowledge;
  regs.r[1] = (int)message;
  regs.r[2] = message->hdr.sender;		// broadcast

  TRACE("message_size %i", message->hdr.size);

  Error(_kernel_swi(Wimp_SendMessage, &regs, &regs));

  print_render();
}

void
drawfile::OnHasBeenHiddenEvent( WindowHasBeenHiddenEvent *has_been_hidden, IdBlock *idb )
{
  Window::OnHasBeenHiddenEvent( has_been_hidden, idb );
  delete this;
}

void
drawfile::zoom(int in_out)
{
  if (in_out){	// if out
  	if (ratio[1] > 1) ratio[1] -= 1;
  	else ratio[0] += 1;
  	set_A4_extent_with_zoom();	// if zoom out redraw on larger size
  	SetExtent(0, &w_extent);
  	ForceRedraw(0, &w_extent);
  } else {	// zoom in
   	if (ratio[0] > 1) ratio[0] -= 1;
  	else ratio[1] += 1;
        ForceRedraw(0, &w_extent);
  	set_A4_extent_with_zoom();
  	SetExtent(0, &w_extent);	// otherwise on the larger size
  }
}

void
drawfile::request_print(void)
{
  WimpMessage  message;
 _kernel_swi_regs regs;		//PrintSave request
  char path[FILE_PATH_LENGTH];

  sprintf(path, "%s.%s", WORKING_DIR, file_name);

  abc_task.recorded_message_list.RegisterWaitingForMessage(mOID, Wimp_MPrintTypeOdd);
  abc_task.recorded_message_list.RegisterWaitingForMessage(mOID, Wimp_MPrintError);

    message.hdr.size = 256; //just header sizeof(message);
    message.hdr.my_ref = 0;
    message.hdr.your_ref = 0;
    message.hdr.action_code = Wimp_MPrintSave;
    message.data.data_save.estimated_size = f_size;
    message.data.data_save.file_type = 0xAFF;	// draw file type
    sprintf(message.data.data_save.leaf_name,"%s", path);

    regs.r[0] = Wimp_EUserMessageRecorded;  	//code user recorded or Acknowledge;
    regs.r[1] = (int)&message;
    regs.r[2] = 0;				// broadcast

    Error(_kernel_swi(Wimp_SendMessage, &regs, &regs));
}

_kernel_oserror*
drawfile::Render(int *matrix, BBox *extent)
{
    _kernel_swi_regs reg;

      reg.r[0] = 0;
      reg.r[1] = (int)allocated_file;
      reg.r[2] = f_size;
      reg.r[3] = (int)matrix;
      reg.r[4] = (int)extent;
      reg.r[5] = 0;

      return _kernel_swi(DrawFile_Render, &reg, &reg);
}

void
drawfile::redraw()
{
   int matrix[6];	// transformation matrix, see toolbox prm 494.
   WimpGetWindowStateBlock state;
   WimpRedrawWindowBlock block;
  _kernel_swi_regs reg;

   Error(GetWimpState(0, &state));

   matrix[0] = matrix[3] = (int)((ratio[0]/(float)ratio[1]) * (1<<16));
   matrix[1] = matrix[2] = 0;
   matrix[4] = (state.visible_area.xmin - state.xscroll) * 256;
   matrix[5] = (state.visible_area.ymax - state.yscroll) * 256;

   Error(GetWimpHandle(0, &(block.window_handle) ) );
   reg.r[1] = (int)&block;
   Error(_kernel_swi(Wimp_RedrawWindow, &reg, &reg));
   while (reg.r[0])
   {
      Error(Render(matrix, &(block.redraw_area) ));
      reg.r[1] = (int)&block;
      Error(_kernel_swi(Wimp_GetRectangle, &reg, &reg));
   }
}

void
drawfile::print_render()
{
   int job=0;
   int trfm[6];
   int plot_origin[2];
  _kernel_swi_regs regs;
   BBox printable;

   //TRACE("Print Render");

   if (toolbar.stages == NULL){
   	Error(error_construct("Err_Obj"));
   	return;
   }

   set_identity_tran_matrix(trfm);	// initialise the structures

   trfm[4] = plot_origin[0] = printable.xmin = toolbar.stages[toolbar.stage_count].limits.xmin;
   trfm[5] = plot_origin[1] = printable.ymin = toolbar.stages[toolbar.stage_count].limits.ymin;
   printable.xmax = toolbar.stages[toolbar.stage_count].limits.xmax;
   printable.ymax = toolbar.stages[toolbar.stage_count].limits.ymax;

   plot_origin[0] = plot_origin[0] * OS_MILLIPT; // osunit->millipoint
   plot_origin[1] = plot_origin[1] * OS_MILLIPT;
   trfm[4] = trfm[4] * 256;
   trfm[5] = trfm[5] * 256;

   if( (!Error(_kernel_swi(Hourglass_On, &regs, &regs))) &&
       (!Error(_kernel_swi(PDriver_Info, &regs, &regs))) ){

   	TRACE("Printer: %s", regs.r[4]);

   	regs.r[0] = 0xcf;
   	regs.r[1] = (int) "printer:";

   	if (!Error(_kernel_swi(OS_Find, &regs, &regs))){

   		job = regs.r[0];

   		regs.r[1] = (int) "test print";

   		if (Error(_kernel_swi(PDriver_SelectJob, &regs, &regs))){
   	  		print_abort(job);
   	  		return;
   		}

   		regs.r[0] = 0;
   		regs.r[1] = (int)allocated_file;
   		regs.r[2] = f_size;

   		if (Error(_kernel_swi(DrawFile_DeclareFonts, &regs, &regs))){
	  		print_abort(job);
   	  		return;
   		}

   		regs.r[0] = 0;				//bounding box for printable area
   		regs.r[1] = (int) &printable;
   		regs.r[2] = (int) trfm;
   		regs.r[3] = (int) plot_origin;		// the address of 4 and 5 the origin
   		regs.r[4] = BACKGROUND_COLOUR;

   		if (Error(_kernel_swi(PDriver_GiveRectangle, &regs, &regs))){
	  		print_abort(job);
   	 	 	return;
   		}

   		regs.r[0] = 1;	// only one copy
   		regs.r[1] = (int)&printable;
   		regs.r[2] = 0;
   		regs.r[3] = 0;

   		if (Error(_kernel_swi(PDriver_DrawPage, &regs, &regs))){
 	 	 	print_abort(job);
   		  	return;
   		}
  		while (regs.r[0])
   		{
   		   TRACE("printing rectangle %i, %i, %i, %i", printable.xmin, printable.xmax,
   						printable.ymin, printable.ymax);

      			if (Error(Render(0, &printable))){
 	  			print_abort(job);
   	  			return;
   			}
     			regs.r[1] = (int)&printable;
      			if (Error(_kernel_swi(PDriver_GetRectangle, &regs, &regs))){
 	  			print_abort(job);
   	  			return;
   			}
  		}
  	}// end error on file find
   }// end error zone, hourglass and printer info

   if (job) {
      regs.r[0] = job;
      _kernel_swi(PDriver_EndJob, &regs,&regs);
      regs.r[0] = 0;
      regs.r[1] = job;
      _kernel_swi(OS_Find, &regs,&regs);

   }
   Error(_kernel_swi(Hourglass_Off, &regs, &regs));
   next_stage(+1);
}

void
drawfile::print_abort(int job)
{
   _kernel_swi_regs regs;

    regs.r[0] = job;
    Error(_kernel_swi(PDriver_CancelJob, &regs, &regs));
    Error(_kernel_swi(PDriver_AbortJob, &regs,&regs));
      regs.r[0] = 0;
      regs.r[1] = job;
     _kernel_swi(OS_Find, &regs,&regs);

   Error(_kernel_swi(Hourglass_Off, &regs, &regs));
}

void
drawfile::set_identity_tran_matrix(int *matx)
{
  matx[0] = matx[3] = 1<<16;
  matx[1] = matx[2] = matx[4] = matx[5] = 0;
}


int
drawfile::next_stage(int amount)
{
  int end;
  end = toolbar.next_stage(amount);
  if (strcmp(file_name, toolbar.stages[toolbar.stage_count].file_name))
  	load_new_file( toolbar.stages[toolbar.stage_count].file_name );

  return end;
}

void
drawfile::load_new_file(char *s_filename)
{
	//toolbar.stages[toolbar.stage_count].file_name;
	// this does not create an new memory location
	// so if you delete the stage we have a floater

  char path[FILE_PATH_LENGTH];

  file_name = s_filename;	// point to the file in the stages array

  sprintf(path, "%s.%s", WORKING_DIR, file_name);
  f_size = file_size(path);
  if (allocated_file != NULL) {
    	delete allocated_file;
  	ForceRedraw(0, &w_extent);
  }
  allocated_file = new char[f_size];
  file_load(path);
}
