/* > C.DrawExt                                                              */

/* Drawfile extenties. Aanvulling op ACORN draw functie. Worden gebruikt om */
/* diagrammen aan te maken van PSDs. Deze diagrammen worden in de window's  */
/* afgebeeld of kunnen naar disk worden ge-saved.                           */

#include <string.h>
#include <limits.h>
#include <math.h>

#include "werr.h"
#include "os.h"
#include "wimpt.h"
#include "visdelay.h"
#include "heap.h"
#include "image.h"
#include "drawext.h"
#include "font.h"

#include "wimp-funct.h"

int draw_colour              = 0x00000000;     /* Globaal kleur nummer     */
int draw_width               = 0;              /* Globaal line dikte       */
int draw_fill_colour         = -1;             /* Globaal fill kleur       */
int draw_text_col            = 0x00000000;     /* Globaal text kleur       */
int draw_text_background_col = 0xffffff00;     /* Globaal text achtergrond */


/*****************************************************************************/

#define MIN2(x,y)          ((x < y) ? x : y)
#define MAX2(x,y)          ((x > y) ? x : y)

/*****************************************************************************/


int minimum(int aantal,int hoogte[])
{
   int teller;
   int min = INT_MAX;

   for (teller = 0; teller < aantal; teller++)
      if (hoogte[teller] < min)
         min = hoogte[teller];
   return(min);
}

int min3(int a,int b,int c)
{
   int array[4];

   array[0] = a;
   array[1] = b;
   array[2] = c;
   return (minimum(3,array));
}

int min4(int a,int b,int c,int d)
{
   int array[5];

   array[0] = a;
   array[1] = b;
   array[2] = c;
   array[3] = d;
   return (minimum(4,array));
}

int min5(int a,int b,int c,int d,int e)
{
   int array[6];

   array[0] = a;
   array[1] = b;
   array[2] = c;
   array[3] = d;
   array[4] = e;
   return (minimum(5,array));
}


int maximum(int aantal,int hoogte[])
{
   int teller;
   int max = INT_MIN;

   for (teller = 0; teller < aantal; teller++)
      if (hoogte[teller] > max)
         max = hoogte[teller];
   return(max);
}

int max3(int a,int b,int c)
{
   int array[4];

   array[0] = a;
   array[1] = b;
   array[2] = c;
   return (maximum(3,array));
}

int max4(int a,int b,int c,int d)
{
   int array[5];

   array[0] = a;
   array[1] = b;
   array[2] = c;
   array[3] = d;
   return (maximum(4,array));
}

int max5(int a,int b,int c,int d,int e)
{
   int array[6];

   array[0] = a;
   array[1] = b;
   array[2] = c;
   array[3] = d;
   array[4] = e;
   return (maximum(5,array));
}

void set_draw_colour(int colnum)
{
   draw_colour = colnum;
}

void set_draw_fill_colour(int colnum)
{
   draw_fill_colour = colnum;
}

void set_draw_width(int width)
{
   draw_width = width;
}

void set_text_col(int col)
{
   draw_text_col = col;
}

void set_text_background_col(int col)
{
   draw_text_background_col = col;
}

int get_draw_colour()
{
   return( draw_colour );
}

int get_draw_fill_colour()
{
   return( draw_fill_colour );
}

int get_draw_width()
{
   return ( draw_width );
}

int get_text_col()
{
   return ( draw_text_col );
}

int get_text_background_col()
{
   return ( draw_text_background_col );
}

void drawext_init(void)
{
   set_draw_colour(0x00000000);
   set_draw_fill_colour(-1);
   set_draw_width(0);
   set_text_col(0x00000000);
   set_text_background_col(0xffffff00);

}

void init_path_header(draw_pathstrhdr *hdr,int size,int x0,int y0,int x1,
                      int y1)
{
   hdr->tag     = draw_OBJPATH;
   hdr->size    = size;
   hdr->bbox.x0 = draw_screenToDraw(x0);
   hdr->bbox.y0 = draw_screenToDraw(y0);
   hdr->bbox.x1 = draw_screenToDraw(x1);
   hdr->bbox.y1 = draw_screenToDraw(y1);
   hdr->fillcolour = draw_fill_colour;
   hdr->pathcolour = draw_colour;
   hdr->pathwidth  = draw_width;
   hdr->pathstyle.joincapwind = 0;
   hdr->pathstyle.reserved8   = 0;
   hdr->pathstyle.tricapwid   = 0;
   hdr->pathstyle.tricaphei   = 0;
}

void init_path_move(Path_movestr *move,int x,int y)
{
   move->tag = draw_PathMOVE;
   move->x   = draw_screenToDraw(x);
   move->y   = draw_screenToDraw(y);
}

void init_path_line(Path_linestr *line,int x,int y)
{
   line->tag = draw_PathLINE;
   line->x   = draw_screenToDraw(x);
   line->y   = draw_screenToDraw(y);
}

void init_path_term(Path_termstr *term)
{
   term->tag = draw_PathTERM;
}




int line1(diag *diagram,int x0,int y0,int x1,int y1)
{
   draw_object     obj_handle = -1;
   draw_line       object;
   int        minx, miny, maxx, maxy;

   while (diagram->length + sizeof(draw_line) > diagram->size)
   {
      draw_extend_diag(diagram);
   }

   minx = MIN2(x0,x1);
   maxx = MAX2(x0,x1);
   miny = MIN2(y0,y1);
   maxy = MAX2(y0,y1);

   init_path_header(&object.hdr,sizeof(draw_line),minx,miny,maxx,maxy);
   init_path_move(&object.move,x0,y0);
   init_path_line(&object.line,x1,y1);
   init_path_term(&object.term);

   obj_handle = diagram->length;
   memcpy(&diagram->data[diagram->length],&object,object.hdr.size);
   diagram->length = diagram->length + object.hdr.size;
   
   return (obj_handle);
}

int line2(diag *diagram,int x0,int y0,int x1,int y1,int x2,int y2)
{
   draw_object     obj_handle = -1;
   draw_two_lines  object;
   int minx;
   int maxx;
   int miny;
   int maxy;
   
   while (diagram->length + sizeof(draw_two_lines) > diagram->size)
   {
      draw_extend_diag(diagram);
   }
   minx = min3(x0,x1,x2);
   miny = min3(y0,y1,y2);
   maxx = max3(x0,x1,x2);
   maxy = max3(y0,y1,y2);
   init_path_header(&object.hdr,sizeof(draw_two_lines),minx,miny,maxx,maxy);
   init_path_move(&object.move,x0,y0);
   init_path_line(&object.line1,x1,y1);
   init_path_line(&object.line2,x2,y2);
   init_path_term(&object.term);

   obj_handle = diagram->length;
   memcpy(&diagram->data[diagram->length],&object,object.hdr.size);
   diagram->length = diagram->length + object.hdr.size;                            
   return (obj_handle);
}

int line3(diag *diagram,int x0,int y0,int x1,int y1,int x2,int y2,
          int x3,int y3)
{
   draw_object     obj_handle = -1;
   draw_triangle   object;
   int minx;
   int maxx;
   int miny;
   int maxy;
   
   while (diagram->length + sizeof(draw_triangle) > diagram->size)
   {
      draw_extend_diag(diagram);
   }

   minx = min4(x0,x1,x2,x3);
   miny = min4(y0,y1,y2,y3);
   maxx = max4(x0,x1,x2,x3);
   maxy = max4(y0,y1,y2,y3);
   init_path_header(&object.hdr,sizeof(draw_triangle),minx,miny,maxx,maxy);
   init_path_move(&object.move,x0,y0);
   init_path_line(&object.line1,x1,y1);
   init_path_line(&object.line2,x2,y2);
   init_path_line(&object.line3,x3,y3);
   init_path_term(&object.term);

   obj_handle = diagram->length;
   memcpy(&diagram->data[diagram->length],&object,object.hdr.size);
   diagram->length = diagram->length + object.hdr.size;                         
   return (obj_handle);
}
   
int line4(diag *diagram,int x0,int y0,int x1,int y1,int x2,int y2,
          int x3,int y3,int x4,int y4)
{
   draw_object     obj_handle = -1;
   draw_rectangle  object;
   int minx;
   int maxx;
   int miny;
   int maxy;

   while (diagram->length + sizeof(draw_rectangle) > diagram->size)
   {
      draw_extend_diag(diagram);
   }
   minx = min5(x0,x1,x2,x3,x4);
   miny = min5(y0,y1,y2,y3,y4);
   maxx = max5(x0,x1,x2,x3,x4);
   maxy = max5(y0,y1,y2,y3,y4);
   init_path_header(&object.hdr,sizeof(draw_rectangle),minx,miny,maxx,maxy);
   init_path_move(&object.move,x0,y0);
   init_path_line(&object.line1,x1,y1);
   init_path_line(&object.line2,x2,y2);
   init_path_line(&object.line3,x3,y3);
   init_path_line(&object.line4,x4,y4);
   init_path_term(&object.term);

   obj_handle = diagram->length;
   memcpy(&diagram->data[diagram->length],&object,object.hdr.size);
   diagram->length = diagram->length + object.hdr.size;

   return (obj_handle);
}

int rectangle(diag *diagram,int x0,int y0,int x1,int y1)
{
   return (line4(diagram,x0,y0,x0,y1,x1,y1,x1,y0,x0,y0));
}

int triangle(diag *diagram,int x0,int y0,int x1,int y1,int x2,int y2)
{
   return (line3(diagram,x0,y0,x1,y1,x2,y2,x0,y0));
}

void text(diag *diagram,char font_num,int x_points,int y_points,int xpos,
          int ypos,char *string)
{
   draw_text       object;
   font_info       block;
   int             tel;
   int             lengte;

   while (diagram->length + sizeof(draw_text) > diagram->size)
   {
      draw_extend_diag(diagram);
   }
   font_stringbbox(string,&block);
   font_converttoos(block.minx,block.maxx,&block.minx,&block.maxx);
   font_converttoos(block.miny,block.maxy,&block.miny,&block.maxy);

   for (tel =0 ; tel <= 255; tel++)
   {
      object.text[tel] = '\0';
   }

   lengte = strlen(string) + 1;
   while ((lengte % 4) != 0) lengte++;

   object.hdr.tag     = draw_OBJTEXT;
   object.hdr.size    = sizeof(draw_textstrhdr) + lengte;
   object.hdr.bbox.x0 = draw_screenToDraw(xpos + block.minx);
   object.hdr.bbox.y0 = draw_screenToDraw(ypos + block.miny);
   object.hdr.bbox.x1 = draw_screenToDraw(xpos + block.maxx);
   object.hdr.bbox.y1 = draw_screenToDraw(ypos + block.maxy);
   object.hdr.textcolour = draw_text_col;
   object.hdr.background = draw_text_background_col;

   object.hdr.textstyle.fontref    = font_num;
   object.hdr.textstyle.reserved8  = 0;
   object.hdr.textstyle.reserved16 = 0;
   object.hdr.fsizex     = x_points * 640;
   object.hdr.fsizey     = y_points * 640;
   object.hdr.coord.x    = draw_screenToDraw(xpos);
   object.hdr.coord.y    = draw_screenToDraw(ypos);
   strcpy(object.text,string);

   memcpy(&diagram->data[diagram->length],&object,object.hdr.size);
   diagram->length = diagram->length + object.hdr.size;
}

void font_table(diag *diagram,char font_nummer,char *font_name) 
{
   draw_font_list  object;
   int             tel;
   int             lengte;


   while (diagram->length + sizeof(draw_font_list) > diagram->size)
   {
      draw_extend_diag(diagram);
   }
   for (tel =0 ; tel <= strlen(font_name) + 4 && tel < 255 ; tel++)
   {
      object.name[tel] = '\0';
   }

   lengte = sizeof(draw_fontliststrhdr) + sizeof(char) + strlen(font_name) +
            1;
   while ((lengte % 4) != 0) lengte++;

   object.hdr.tag  = draw_OBJFONTLIST;
   object.hdr.size = lengte;   
   object.font_ref = font_nummer;
   strcpy(object.name,font_name);

   memcpy(&diagram->data[diagram->length],&object,object.hdr.size);
   diagram->length = diagram->length + object.hdr.size;
}

void draw_show_error(char *func_name,draw_error *err)
{
   switch (err->type)
   {
      case DrawOSError :
         werr(FALSE,"Function %s, error %d: %s",func_name,
                    err->err.os.errnum,err->err.os.errmess);
         break;

      case DrawOwnError :
         werr(FALSE,"Function %s, draw error %d at location %d",func_name,
                    err->err.draw.code,err->err.draw.location);
         break;
   }
}

void draw_extend_diag(diag *diagram)
{
   char *hulp;

   hulp = (char*)heap_alloc((unsigned int)(diagram->size + DIAGRAM_SIZE));
   if (hulp ==NULL) werr(TRUE,"draw_extender failed");
   memcpy(hulp,diagram->data,diagram->length);
   heap_free(diagram->data);
   diagram->data = hulp;
   diagram->size = diagram->size + DIAGRAM_SIZE;
}
