/* Calibration for EPSON printers
   Created 22.02.2003 T. Milius
   Changed 27.09.2004 T. Milius */
/* (c) Copyright 2003-2004 by Thomas Milius Stade, Germany
   Source must not be altered without agreement of the owner.
   The owner of the source is allowed to use this code inside programs without
   publishing the code of this programs. These programs may be commercial.
   Other developers can use this source freely inside own software if the source
   code of this programs is made public to same conditions like valid to this code
   and no commercial profit is taken from the programs based on this code.

   Code or parts of it are not allowed to be used within GPL code or
   similar licenses which are "infecting" other code and trying to "supersede"
   other licenses. */
/* RISCOS */
/* !!!!!!!!!! libraries !!!!!!!!!! */
/* ---------- ANSI-C ---------- */
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>

/* ------------ RISC OS ------------ */
#include <kernel.h>
#include <swis.h>

/* ------------ Toolbox ------------ */
#include <event.h>
#include <toolbox.h>
#include <wimp.h>
#include <wimplib.h>
#include <menu.h>
#include <gadgets.h>
#include <colourdbox.h>
#include <iconbar.h>

/* ------------ own ------------ */
#include "settings.h"
#include "colour_groups.h"
#include "tb_defs.h"

/* !!!!!!!!!!! definitions !!!!!!!!!! */
/* to clarify reading */
#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif

#define MIN_RGB_COMPONENT_VALUE 0
#define MAX_RGB_COMPONENT_VALUE 255

#define INDETERMINED_DISCTANCE 0x0FFFFFFF

/* Draw file display */
#define SQUARE_SIDE_SIZE 27200

/* required to disable some system commands */
//#define DEBUG_MODE

/* !!!!!!!!!! data structures !!!!!!!!!! */
struct basic_colour_struct {
unsigned long colour_scheme;
unsigned long group_mask;
unsigned long printer_pattern;
long rgb_components[3];
/* 8 Bit trailing digits */
long component_relation[3];
long base_value;
int cartridge;
};

struct colour_struct {
unsigned long group_mask;
unsigned long printer_pattern;
int number_of_used_cartridges;
long rgb_components[3];
long rgb_range_min[3], rgb_range_max[3];
long paper_colour_fraction;
};

struct {
unsigned long colour_scheme;
long intensity_reduction;
long calibration;
int bits_per_pixel;
int pixel_pad_bits;
int shift_pixel_pad_bits;
int number_of_intensities;
int intensity_mode;
int number_of_cartridges;
int number_of_basic_colours;
int black_mode_flag;
struct basic_colour_struct *basic_colour;
int max_number_of_printable_colours;
int number_of_printable_colours;
struct colour_struct *printable_colour;
/* Printer colour */
char printer_name[40];
char calibration_file_name[500];
char extern_calibration_file_name[500];
ObjectId window;
/* Colour checking states */
ObjectId colour_dbox;
int actual_cartridge;
int actual_colour;
int actual_column;
/* Program control */
int calibration_process_flag;
int shutdown_flag;
} common;

/* ---------- RISCOS Wimp Toolbox Communication ---------- */
static WimpPollBlock poll_block;
static MessagesFD    messages;
static IdBlock       id_block;

_kernel_oserror app_error;

/* !!!!!!!!!! support functions !!!!!!!!!! */
int show_message(int message_number,
                 ...)
{
va_list args;
char message_token[20];
char format[200];
_kernel_swi_regs regs;

sprintf(message_token,
        "Error_%d",
        message_number);
regs.r[0]=(int) messages.data;
regs.r[1]=(int) message_token;
regs.r[2]=(int) format;
regs.r[3]=199;
regs.r[4]=0;
regs.r[5]=0;
regs.r[6]=0;
regs.r[7]=0;
_kernel_swi(MessageTrans_Lookup, &regs, &regs);
va_start(args, message_number);
vsprintf(app_error.errmess, format, args);
va_end(args);
app_error.errnum=0;
wimp_report_error(&app_error,
                  0,
                  0,
                  APPLICATION_NAME,
                  0,
                  0);
return TRUE;
}

char *get_pad_bit_values(int number_of_bits)
{

/* one smaller than number of bits */
switch(number_of_bits) {
  case 1: {
    return "0";
    }
  break;
  case 2: {
    return "-1,0,1";
    }
  break;
  case 4: {
    return "-3,-2,-1,0,1,2,3";
    }
  break;
  default: {
    return "3,-2,-1,0,1,2,3";
    }
  }
}

int find_next_cartridge_colour(int actual_cartridge,
                              int last_colour)
{
int i;

i=last_colour + 1;
if (i < 1) i=1;
while (i < common.number_of_basic_colours) {
  if (common.basic_colour[i].cartridge == actual_cartridge) return i;
  i++;
  }
return i;
}

char *get_catridge_name(unsigned long colour_scheme,
                        char *target_string)
{
static char cartridge_name[40];

switch(colour_scheme) {
  case 0x00000000: {
    strcpy(cartridge_name, "Paper Colour");
    }
  break;
  case 0x00000001: {
    strcpy(cartridge_name, "Black");
    }
  break;
  case 0x00000002: {
    strcpy(cartridge_name, "Grey");
    }
  break;
  case 0x00000004: {
    strcpy(cartridge_name, "light Grey");
    }
  break;
  case 0x00000008: {
    strcpy(cartridge_name, "Cyan");
    }
  break;
  case 0x00000010: {
    strcpy(cartridge_name, "Magenta");
    }
  break;
  case 0x00000020: {
    strcpy(cartridge_name, "Yellow");
    }
  break;
  case 0x00000040: {
    strcpy(cartridge_name, "light Cyan");
    }
  break;
  case 0x00000080: {
    strcpy(cartridge_name, "light Magenta");
    }
  break;
  case 0x00000100: {
    strcpy(cartridge_name, "light Yellow");
    }
  break;
  case 0x00000200: {
    strcpy(cartridge_name, "Green");
    }
  break;
  case 0x00000400: {
    strcpy(cartridge_name, "Orange");
    }
  break;
  case 0x00000800: {
    strcpy(cartridge_name, "light Green");
    }
  break;
  case 0x00001000: {
    strcpy(cartridge_name, "light Orange");
    }
  break;
  default: {
    strcpy(cartridge_name, "unknown Colour");
    }
  }
if (target_string) {
  strcpy(target_string, cartridge_name);
  }
return cartridge_name;
}

int modify_calibration_file(int no_backup_flag,
                            int write_data_flag,
                            char *import_file_name)
{
int i, j;
int actual_colour;
int scan_flag;
int max_component_value, min_component_value;
char old_calibration_file_name[300], new_calibration_file_name[300];
char file_line[512];
char command[300];
FILE *old_calibration_file, *new_calibration_file;

/* All other information inside the file
   must be kept only the block with the printable colours
   must be replaced or added  */
/* The colour information is stored inside a block which
   is preceeded by the tag

   printable_colours_start

   and terminated by the tag

   printable_colours_end

   Each line has the format

   r g b r_min r_max g_min g_max b_min b_max printer_pattern */
sprintf(old_calibration_file_name,
        "<PDPEICal$ConfDir>.%s",
        common.printer_name);
sprintf(new_calibration_file_name,
        "<Wimp$ScrapDir>.PDPEICal.%s",
        common.printer_name);
if ((new_calibration_file=fopen(new_calibration_file_name,
                                "w")) == NULL) {
  show_message(4, new_calibration_file_name);
  if (common.printable_colour) {
    free(common.printable_colour);
    }
  return FALSE;
  }
if ((old_calibration_file=fopen(old_calibration_file_name,
                                "r")) == NULL) {
  /* Copy default file */
  sprintf(command,
          "Copy <PDPEICal$Dir>.Resources.CalibDef <PDPEICal$ConfDir>.%s ~CFN~V",
          common.printer_name);
  system(command);
  if ((old_calibration_file=fopen(old_calibration_file_name,
                                  "r")) == NULL) {
    fclose(new_calibration_file);
    show_message(5, old_calibration_file);
    if (common.printable_colour) {
      free(common.printable_colour);
      }
    return FALSE;
    }
  }
else {
  /* Make a backup of old file inside PDPEICal.Resources.Calib
     called "Backup" for recovery purposes. Only at first
     step before generating the setup file. */
  if (!no_backup_flag) {
    sprintf(command,
            "Copy <PDPEICal$ConfDir>.%s <PDPEICal$Dir>.Resources.Calibs.Backup ~CFN~V",
            common.printer_name);
#ifndef DEBUG_MODE
    system(command);
#endif
    }
  }
/* Scan old calibration file until the according block */
scan_flag=TRUE;
while (scan_flag) {
  if (fgets(file_line,
            511,
            old_calibration_file)) {
    if (file_line[strlen(file_line)-1] == '\n') {
      file_line[strlen(file_line)-1]='\0';
      }
    /* check for tag */
    if (strncmp(file_line,
                FILE_COLOUR_CALIBRATION_START,
                strlen(FILE_COLOUR_CALIBRATION_START)) == 0) {
      long actual_calibration;

      /* Determine number of calibration */
      actual_calibration=atol(&file_line[strlen(FILE_COLOUR_CALIBRATION_START)]);
      /* Check whether calibration is required calibration */
      if (actual_calibration == common.calibration) {
        scan_flag=FALSE;
        }
      else {
        fprintf(new_calibration_file,
                "%s\n",
                file_line);
        }
      }
    else {
      fprintf(new_calibration_file,
              "%s\n",
              file_line);
      }
    }
  else {
    scan_flag=FALSE;
    }
  }
/* Skip block */
scan_flag=TRUE;
while (scan_flag) {
  if (fgets(file_line,
            511,
            old_calibration_file)) {
    if (file_line[strlen(file_line)-1] == '\n') {
      file_line[strlen(file_line)-1]='\0';
      }
    /* check for tag */
    if (strcmp(file_line, FILE_COLOUR_CALIBRATION_END) == 0) {
      scan_flag=FALSE;
      }
    }
  else {
    scan_flag=FALSE;
    }
  }
if (write_data_flag) {
  if (common.calibration == 0) {
    fprintf(new_calibration_file,
            "%s\n",
            FILE_COLOUR_CALIBRATION_START);
    }
  else
    {
    fprintf(new_calibration_file,
            "%s %ld\n",
            FILE_COLOUR_CALIBRATION_START,
            common.calibration);
    }
  /* Produce a generation protocol as comments */
  fprintf(new_calibration_file,
          "# Bits per Pixel: %d\n",
          common.bits_per_pixel);
  fprintf(new_calibration_file,
          "# Pad Bits per Pixel: %d\n",
          common.pixel_pad_bits);
  fprintf(new_calibration_file,
          "# Number of Cartridges: %d\n",
          common.number_of_cartridges);
  fprintf(new_calibration_file,
          "# Number of Intensities: %d\n",
          common.number_of_intensities - 1);
  fprintf(new_calibration_file,
          "# Intensity Reduction: %ld\n",
          common.intensity_reduction);
  if (import_file_name &&
      (strlen(import_file_name) > 0)) {
    fprintf(new_calibration_file,
            "# Data from extern calibration file %s\n",
            import_file_name);
    }
  fprintf(new_calibration_file,
          "# Number of printable colours: %d\n",
          common.number_of_printable_colours);
  for (i=0; i < common.number_of_cartridges; i++) {
    j=1;
    actual_colour=-1;
    while(actual_colour < common.number_of_basic_colours) {
      actual_colour=find_next_cartridge_colour(i,
                                              actual_colour);
      if (actual_colour < common.number_of_basic_colours) {
        fprintf(new_calibration_file,
                "# Colour: %s Intensity: %d R: %.1f G: %.1f B: %.1f\n",
                get_catridge_name(common.basic_colour[actual_colour].colour_scheme,
                                  NULL),
                j,
                (double) common.basic_colour[actual_colour].rgb_components[0]*100/MAX_RGB_COMPONENT_VALUE,
                (double) common.basic_colour[actual_colour].rgb_components[1]*100/MAX_RGB_COMPONENT_VALUE,
                (double) common.basic_colour[actual_colour].rgb_components[2]*100/MAX_RGB_COMPONENT_VALUE);
        j++;
        }
      }
    }
  for (actual_colour=0; actual_colour<common.number_of_printable_colours; actual_colour++) {
    for (i=0; i < 3; i++) {
      fprintf(new_calibration_file,
              "%ld ",
              common.printable_colour[actual_colour].rgb_components[i]);
      }
    for (i=0; i < 3; i++) {
      /* The print colour point is always included */
      min_component_value=common.printable_colour[actual_colour].rgb_components[i];
      max_component_value=common.printable_colour[actual_colour].rgb_components[i];
      /* At first calibration step every colour must be exactly represented.
         So there is no need for cubes. */
      if (no_backup_flag) {
        min_component_value=common.printable_colour[actual_colour].rgb_range_min[i];
        max_component_value=common.printable_colour[actual_colour].rgb_range_max[i];
        }
      fprintf(new_calibration_file,
              "%d %d ",
              min_component_value,
              max_component_value);
      }
    fprintf(new_calibration_file,
            "%lx %lx %ld\n",
            common.printable_colour[actual_colour].printer_pattern,
            common.printable_colour[actual_colour].group_mask,
            common.printable_colour[actual_colour].paper_colour_fraction);
    }
  fprintf(new_calibration_file,
          "%s\n",
          FILE_COLOUR_CALIBRATION_END);
  }
/* Copy the remaing part of the calibration file */
scan_flag=TRUE;
while (scan_flag) {
  if (fgets(file_line,
            511,
            old_calibration_file)) {
    fprintf(new_calibration_file,
            "%s",
            file_line);
    }
  else {
    scan_flag=FALSE;
    }
  }
fclose(old_calibration_file);
fclose(new_calibration_file);
/* Replace old file by new one */
remove(old_calibration_file_name);
rename(new_calibration_file_name, old_calibration_file_name);
return TRUE;
}

/* Base value concept:
   The base value is always the lightest value of a component
   of a catridge.

   Each catridge has a fixed number of intensities which
   it can print. You can think of several concepts how
   to realize various intensities. EPSON eg. uses a
   logarithmic model but you can also think about a
   linear concept.

   You might have several colour component stages represented
   by several catridges. This is taken into account by the
   "level" parameter. */
long calculate_base_value(int required_level)
{
int actual_level;
long base_value;

actual_level=-1;
base_value=MAX_RGB_COMPONENT_VALUE - MIN_RGB_COMPONENT_VALUE + 1;
do {
  actual_level++;
  switch(common.intensity_mode) {
    case 0: {
      if (actual_level == 0) {
        base_value=base_value/(1<<(common.number_of_intensities - 2));
        }
      else {
        base_value=base_value/(1<<(common.number_of_intensities - 1));
        }
      }
    break;
    case 1: {
      if (actual_level == 0) {
        base_value=base_value/(common.number_of_intensities - 1);
        }
      else {
        base_value=base_value/common.number_of_intensities;
        }
      }
    break;
    }
  }
while(actual_level < required_level);
return base_value;
}

int set_basic_colours(unsigned long colour_scheme)
{
int i;
int i_component;
int actual_cartridge;
unsigned long group_mask_union;

/* Printer Colours are determined by color_scheme
   Bit  0 - full Black
   Bit  1 - light Black
   Bit  2 - very light Black
   Bit  3 - full Cyan
   Bit  4 - full Magenta
   Bit  5 - full Yellow
   Bit  6 - light Cyan
   Bit  7 - light Magenta
   Bit  8 - light Yellow
   Bit  9 - full Orange
   Bit 10 - full Green
   Bit 11 - light Orange
   Bit 12 - light Green

   Note that these terms are relative eg. there are still
   tries to generate the blackest black.

   Note also that the paper colour is counted as one separate
   colour but not as a cartridge. */
group_mask_union=0;
common.number_of_cartridges=0;
for (i=0; i < 32; i++) {
  if ((colour_scheme>>i) & 0x00000001) {
    common.number_of_cartridges++;
    }
  }
if ((common.basic_colour=malloc(sizeof(struct basic_colour_struct) * (common.number_of_cartridges*common.number_of_intensities + 1))) == NULL) {
  return FALSE;
  }
common.number_of_basic_colours=0;
actual_cartridge=0;
/* Paper colour */
common.basic_colour[common.number_of_basic_colours].colour_scheme=0;
common.basic_colour[common.number_of_basic_colours].group_mask=COLOUR_GROUP_PAPER_COLOUR;
group_mask_union|=common.basic_colour[common.number_of_basic_colours].group_mask;
common.basic_colour[common.number_of_basic_colours].printer_pattern=0x00000000;
common.basic_colour[common.number_of_basic_colours].rgb_components[0]=MAX_RGB_COMPONENT_VALUE;
common.basic_colour[common.number_of_basic_colours].rgb_components[1]=MAX_RGB_COMPONENT_VALUE;
common.basic_colour[common.number_of_basic_colours].rgb_components[2]=MAX_RGB_COMPONENT_VALUE;
common.basic_colour[common.number_of_basic_colours].cartridge=-1;
common.number_of_basic_colours++;
/* Build a colour for each cartridge with smallest intensity first.
   This means smallest intensity gets number 0 and the colours
   are getting biggest possible value because they are close
   to White. */
if (colour_scheme & 0x00000001) {
  /* full Black */
  common.basic_colour[common.number_of_basic_colours].colour_scheme=0x00000001;
  common.basic_colour[common.number_of_basic_colours].group_mask=COLOUR_GROUP_BLACK_GROUP;
  group_mask_union|=common.basic_colour[common.number_of_basic_colours].group_mask;
  common.basic_colour[common.number_of_basic_colours].printer_pattern=(1<<(actual_cartridge*common.bits_per_pixel + common.shift_pixel_pad_bits));
  common.basic_colour[common.number_of_basic_colours].component_relation[0]=0x00000100;
  common.basic_colour[common.number_of_basic_colours].component_relation[1]=0x00000100;
  common.basic_colour[common.number_of_basic_colours].component_relation[2]=0x00000100;
  common.basic_colour[common.number_of_basic_colours].base_value=calculate_base_value(0);
  common.basic_colour[common.number_of_basic_colours].cartridge=actual_cartridge;
  common.number_of_basic_colours++;
  actual_cartridge++;
  }
if (colour_scheme & 0x00000002) {
  /* light Black */
  common.basic_colour[common.number_of_basic_colours].colour_scheme=0x00000002;
  common.basic_colour[common.number_of_basic_colours].group_mask=COLOUR_GROUP_BLACK_GROUP;
  group_mask_union|=common.basic_colour[common.number_of_basic_colours].group_mask;
  common.basic_colour[common.number_of_basic_colours].printer_pattern=(1<<(actual_cartridge*common.bits_per_pixel + common.shift_pixel_pad_bits));
  common.basic_colour[common.number_of_basic_colours].component_relation[0]=0x00000100;
  common.basic_colour[common.number_of_basic_colours].component_relation[1]=0x00000100;
  common.basic_colour[common.number_of_basic_colours].component_relation[2]=0x00000100;
  common.basic_colour[common.number_of_basic_colours].base_value=calculate_base_value(1);
  common.basic_colour[common.number_of_basic_colours].cartridge=actual_cartridge;
  common.number_of_basic_colours++;
  actual_cartridge++;
  }
if (colour_scheme & 0x00000004) {
  /* very light Black */
  common.basic_colour[common.number_of_basic_colours].colour_scheme=0x00000004;
  common.basic_colour[common.number_of_basic_colours].group_mask=COLOUR_GROUP_BLACK_GROUP;
  group_mask_union|=common.basic_colour[common.number_of_basic_colours].group_mask;
  common.basic_colour[common.number_of_basic_colours].printer_pattern=(1<<(actual_cartridge*common.bits_per_pixel + common.shift_pixel_pad_bits));
  common.basic_colour[common.number_of_basic_colours].component_relation[0]=0x00000100;
  common.basic_colour[common.number_of_basic_colours].component_relation[1]=0x00000100;
  common.basic_colour[common.number_of_basic_colours].component_relation[2]=0x00000100;
  common.basic_colour[common.number_of_basic_colours].base_value=calculate_base_value(2);
  common.basic_colour[common.number_of_basic_colours].cartridge=actual_cartridge;
  common.number_of_basic_colours++;
  actual_cartridge++;
  }
if (colour_scheme & 0x00000008) {
  /* full Cyan */
  common.basic_colour[common.number_of_basic_colours].colour_scheme=0x00000008;
  common.basic_colour[common.number_of_basic_colours].group_mask=COLOUR_GROUP_CYAN_GROUP;
  group_mask_union|=common.basic_colour[common.number_of_basic_colours].group_mask;
  common.basic_colour[common.number_of_basic_colours].printer_pattern=(1<<(actual_cartridge*common.bits_per_pixel + common.shift_pixel_pad_bits));
  common.basic_colour[common.number_of_basic_colours].component_relation[0]=0x00000100;
  common.basic_colour[common.number_of_basic_colours].component_relation[1]=0x00000000;
  common.basic_colour[common.number_of_basic_colours].component_relation[2]=0x00000000;
  common.basic_colour[common.number_of_basic_colours].base_value=calculate_base_value(0);
  common.basic_colour[common.number_of_basic_colours].cartridge=actual_cartridge;
  common.number_of_basic_colours++;
  actual_cartridge++;
  }
if (colour_scheme & 0x00000010) {
  /* full Magenta */
  common.basic_colour[common.number_of_basic_colours].colour_scheme=0x00000010;
  common.basic_colour[common.number_of_basic_colours].group_mask=COLOUR_GROUP_MAGENTA_GROUP;
  group_mask_union|=common.basic_colour[common.number_of_basic_colours].group_mask;
  common.basic_colour[common.number_of_basic_colours].printer_pattern=(1<<(actual_cartridge*common.bits_per_pixel + common.shift_pixel_pad_bits));
  common.basic_colour[common.number_of_basic_colours].component_relation[0]=0x00000000;
  common.basic_colour[common.number_of_basic_colours].component_relation[1]=0x00000100;
  common.basic_colour[common.number_of_basic_colours].component_relation[2]=0x00000000;
  common.basic_colour[common.number_of_basic_colours].base_value=calculate_base_value(0);
  common.basic_colour[common.number_of_basic_colours].cartridge=actual_cartridge;
  common.number_of_basic_colours++;
  actual_cartridge++;
  }
if (colour_scheme & 0x00000020) {
  /* full Yellow */
  common.basic_colour[common.number_of_basic_colours].colour_scheme=0x00000020;
  common.basic_colour[common.number_of_basic_colours].group_mask=COLOUR_GROUP_YELLOW_GROUP;
  group_mask_union|=common.basic_colour[common.number_of_basic_colours].group_mask;
  common.basic_colour[common.number_of_basic_colours].printer_pattern=(1<<(actual_cartridge*common.bits_per_pixel + common.shift_pixel_pad_bits));
  common.basic_colour[common.number_of_basic_colours].component_relation[0]=0x00000000;
  common.basic_colour[common.number_of_basic_colours].component_relation[1]=0x00000000;
  common.basic_colour[common.number_of_basic_colours].component_relation[2]=0x00000100;
  common.basic_colour[common.number_of_basic_colours].base_value=calculate_base_value(0);
  common.basic_colour[common.number_of_basic_colours].cartridge=actual_cartridge;
  common.number_of_basic_colours++;
  actual_cartridge++;
  }
if (colour_scheme & 0x00000040) {
  /* light Cyan */
  common.basic_colour[common.number_of_basic_colours].colour_scheme=0x00000040;
  common.basic_colour[common.number_of_basic_colours].group_mask=COLOUR_GROUP_CYAN_GROUP;
  group_mask_union|=common.basic_colour[common.number_of_basic_colours].group_mask;
  common.basic_colour[common.number_of_basic_colours].printer_pattern=(1<<(actual_cartridge*common.bits_per_pixel + common.shift_pixel_pad_bits));
  common.basic_colour[common.number_of_basic_colours].component_relation[0]=0x00000100;
  common.basic_colour[common.number_of_basic_colours].component_relation[1]=0x00000000;
  common.basic_colour[common.number_of_basic_colours].component_relation[2]=0x00000000;
  common.basic_colour[common.number_of_basic_colours].base_value=calculate_base_value(1);
  common.basic_colour[common.number_of_basic_colours].cartridge=actual_cartridge;
  common.number_of_basic_colours++;
  actual_cartridge++;
  }
if (colour_scheme & 0x00000080) {
  /* light Magenta */
  common.basic_colour[common.number_of_basic_colours].colour_scheme=0x00000080;
  common.basic_colour[common.number_of_basic_colours].group_mask=COLOUR_GROUP_MAGENTA_GROUP;
  group_mask_union|=common.basic_colour[common.number_of_basic_colours].group_mask;
  common.basic_colour[common.number_of_basic_colours].printer_pattern=(1<<(actual_cartridge*common.bits_per_pixel + common.shift_pixel_pad_bits));
  common.basic_colour[common.number_of_basic_colours].component_relation[0]=0x00000000;
  common.basic_colour[common.number_of_basic_colours].component_relation[1]=0x00000100;
  common.basic_colour[common.number_of_basic_colours].component_relation[2]=0x00000000;
  common.basic_colour[common.number_of_basic_colours].base_value=calculate_base_value(1);
  common.basic_colour[common.number_of_basic_colours].cartridge=actual_cartridge;
  common.number_of_basic_colours++;
  actual_cartridge++;
  }
if (colour_scheme & 0x00000100) {
  /* light Yellow */
  common.basic_colour[common.number_of_basic_colours].colour_scheme=0x00000100;
  common.basic_colour[common.number_of_basic_colours].group_mask=COLOUR_GROUP_YELLOW_GROUP;
  group_mask_union|=common.basic_colour[common.number_of_basic_colours].group_mask;
  common.basic_colour[common.number_of_basic_colours].printer_pattern=(1<<(actual_cartridge*common.bits_per_pixel + common.shift_pixel_pad_bits));
  common.basic_colour[common.number_of_basic_colours].component_relation[0]=0x00000000;
  common.basic_colour[common.number_of_basic_colours].component_relation[1]=0x00000000;
  common.basic_colour[common.number_of_basic_colours].component_relation[2]=0x00000100;
  common.basic_colour[common.number_of_basic_colours].base_value=calculate_base_value(1);
  common.basic_colour[common.number_of_basic_colours].cartridge=actual_cartridge;
  common.number_of_basic_colours++;
  actual_cartridge++;
  }
if (colour_scheme & 0x00000200) {
  /* Full Orange */
  common.basic_colour[common.number_of_basic_colours].colour_scheme=0x00000200;
  common.basic_colour[common.number_of_basic_colours].group_mask=COLOUR_GROUP_RGB_GROUP;
  group_mask_union|=common.basic_colour[common.number_of_basic_colours].group_mask;
  common.basic_colour[common.number_of_basic_colours].printer_pattern=(1<<(actual_cartridge*common.bits_per_pixel + common.shift_pixel_pad_bits));
  common.basic_colour[common.number_of_basic_colours].component_relation[0]=0x00000000;
  common.basic_colour[common.number_of_basic_colours].component_relation[1]=0x00000044;
  common.basic_colour[common.number_of_basic_colours].component_relation[2]=0x00000100;
  common.basic_colour[common.number_of_basic_colours].base_value=calculate_base_value(0);
  common.basic_colour[common.number_of_basic_colours].cartridge=actual_cartridge;
  common.number_of_basic_colours++;
  actual_cartridge++;
  }
if (colour_scheme & 0x00000400) {
  /* Full Green */
  common.basic_colour[common.number_of_basic_colours].colour_scheme=0x00000400;
  common.basic_colour[common.number_of_basic_colours].group_mask=COLOUR_GROUP_RGB_GROUP;
  group_mask_union|=common.basic_colour[common.number_of_basic_colours].group_mask;
  common.basic_colour[common.number_of_basic_colours].printer_pattern=(1<<(actual_cartridge*common.bits_per_pixel + common.shift_pixel_pad_bits));
  common.basic_colour[common.number_of_basic_colours].component_relation[0]=0x00000100;
  common.basic_colour[common.number_of_basic_colours].component_relation[1]=0x00000000;
  common.basic_colour[common.number_of_basic_colours].component_relation[2]=0x00000100;
  common.basic_colour[common.number_of_basic_colours].base_value=calculate_base_value(0);
  common.basic_colour[common.number_of_basic_colours].cartridge=actual_cartridge;
  common.number_of_basic_colours++;
  actual_cartridge++;
  }
if (colour_scheme & 0x00000800) {
  /* Light Orange */
  common.basic_colour[common.number_of_basic_colours].colour_scheme=0x00000800;
  common.basic_colour[common.number_of_basic_colours].group_mask=COLOUR_GROUP_RGB_GROUP;
  group_mask_union|=common.basic_colour[common.number_of_basic_colours].group_mask;
  common.basic_colour[common.number_of_basic_colours].printer_pattern=(1<<(actual_cartridge*common.bits_per_pixel + common.shift_pixel_pad_bits));
  common.basic_colour[common.number_of_basic_colours].component_relation[0]=0x00000000;
  common.basic_colour[common.number_of_basic_colours].component_relation[1]=0x00000044;
  common.basic_colour[common.number_of_basic_colours].component_relation[2]=0x00000100;
  common.basic_colour[common.number_of_basic_colours].base_value=calculate_base_value(1);
  common.basic_colour[common.number_of_basic_colours].cartridge=actual_cartridge;
  common.number_of_basic_colours++;
  actual_cartridge++;
  }
if (colour_scheme & 0x00001000) {
  /* Light Green */
  common.basic_colour[common.number_of_basic_colours].colour_scheme=0x00001000;
  common.basic_colour[common.number_of_basic_colours].group_mask=COLOUR_GROUP_RGB_GROUP;
  group_mask_union|=common.basic_colour[common.number_of_basic_colours].group_mask;
  common.basic_colour[common.number_of_basic_colours].printer_pattern=(1<<(actual_cartridge*common.bits_per_pixel + common.shift_pixel_pad_bits));
  common.basic_colour[common.number_of_basic_colours].component_relation[0]=0x00000100;
  common.basic_colour[common.number_of_basic_colours].component_relation[1]=0x00000000;
  common.basic_colour[common.number_of_basic_colours].component_relation[2]=0x00000100;
  common.basic_colour[common.number_of_basic_colours].base_value=calculate_base_value(1);
  common.basic_colour[common.number_of_basic_colours].cartridge=actual_cartridge;
  common.number_of_basic_colours++;
  actual_cartridge++;
  }
if ((group_mask_union & COLOUR_GROUP_BLACK_GROUP) != 0) {
  common.black_mode_flag=TRUE;
  }
else {
  common.black_mode_flag=FALSE;
  }
/* Build the RGB components for all the basic colours until now. */
/* Number of cartridges is one smaller than number of
   basic colours. 0 is the paper colour which has already
   got its components. */
for (actual_cartridge=1; actual_cartridge <= common.number_of_cartridges; actual_cartridge++) {
  for (i_component=0; i_component < 3; i_component++) {
    common.basic_colour[actual_cartridge].rgb_components[i_component]=common.basic_colour[actual_cartridge].base_value * common.basic_colour[actual_cartridge].component_relation[i_component];
    /* Assume that result is always positive */
    common.basic_colour[actual_cartridge].rgb_components[i_component]>>=8;
    if (common.basic_colour[actual_cartridge].rgb_components[i_component] > MAX_RGB_COMPONENT_VALUE) {
      common.basic_colour[actual_cartridge].rgb_components[i_component]=MAX_RGB_COMPONENT_VALUE;
      }
    common.basic_colour[actual_cartridge].rgb_components[i_component]=MAX_RGB_COMPONENT_VALUE - common.basic_colour[actual_cartridge].rgb_components[i_component];
    }
  }
/* From the basic colours with smallest intensity build
   the colours with the remaining intensities.

   Concept:
   Colours are given by base value. This determines
   the smallest intesity of the colour. The other
   intensities are determined by a multiple of that
   base value. In which way is determined by the mode.
   One case is doubling the intensity at each stage. The other
   case provides linear increasing of the intensity. */
/* Number of cartridges is one smaller than number of
   basic colours. 0 is the paper colour which is not
   having other intensities. So start at 1. */
for (actual_cartridge=1; actual_cartridge <= common.number_of_cartridges; actual_cartridge++) {
  /* Special exception:
     Loop below is not evaluted in case that number of intensities is 2 or smaller.
     Therefore the pure black mode must be added at here. Black is also pure black in such
     cases */
  if (common.number_of_intensities <= 2) {
    if (common.basic_colour[actual_cartridge].group_mask == COLOUR_GROUP_BLACK_GROUP) {
      common.basic_colour[actual_cartridge].group_mask=COLOUR_GROUP_BLACK_GROUP|COLOUR_GROUP_PURE_BLACK;
      }
    }
  else {
    for (i=2; i < common.number_of_intensities; i++) {
      common.basic_colour[common.number_of_basic_colours].colour_scheme=common.basic_colour[actual_cartridge].colour_scheme;
      if ((common.basic_colour[actual_cartridge].group_mask == COLOUR_GROUP_BLACK_GROUP) &&
          (i == (common.number_of_intensities - 1))) {
        /* Special exception at pure black */
        common.basic_colour[common.number_of_basic_colours].group_mask=COLOUR_GROUP_BLACK_GROUP|COLOUR_GROUP_PURE_BLACK;
        }
      else {
        common.basic_colour[common.number_of_basic_colours].group_mask=common.basic_colour[actual_cartridge].group_mask & COLOUR_GROUP_COMPONENT_MASK;
        }
      common.basic_colour[common.number_of_basic_colours].printer_pattern=(i<<(common.basic_colour[actual_cartridge].cartridge*common.bits_per_pixel + common.shift_pixel_pad_bits));
      common.basic_colour[common.number_of_basic_colours].cartridge=common.basic_colour[actual_cartridge].cartridge;
      for (i_component=0; i_component < 3; i_component++) {
        switch(common.intensity_mode) {
          case 0: {
            common.basic_colour[common.number_of_basic_colours].rgb_components[i_component]=common.basic_colour[actual_cartridge].base_value * (1<<(i-1)) * common.basic_colour[actual_cartridge].component_relation[i_component];
            }
          break;
          case 1: {
            common.basic_colour[common.number_of_basic_colours].rgb_components[i_component]=common.basic_colour[actual_cartridge].base_value * i * common.basic_colour[actual_cartridge].component_relation[i_component];
            }
          break;
          }
        /* Assume that result is always positive */
        common.basic_colour[common.number_of_basic_colours].rgb_components[i_component]>>=8;
        if (common.basic_colour[common.number_of_basic_colours].rgb_components[i_component] > MAX_RGB_COMPONENT_VALUE) {
          common.basic_colour[common.number_of_basic_colours].rgb_components[i_component]=MAX_RGB_COMPONENT_VALUE;
          }
        common.basic_colour[common.number_of_basic_colours].rgb_components[i_component]=MAX_RGB_COMPONENT_VALUE - common.basic_colour[common.number_of_basic_colours].rgb_components[i_component];
        }
      common.number_of_basic_colours++;
      }
    }
  }
return TRUE;
}

/* Checks whether there is storage for an additional element
   and expands it if necassary. */
int check_colour_storage(void)
{
struct colour_struct *new_storage;

if (common.number_of_printable_colours < common.max_number_of_printable_colours) {
  return TRUE;
  }
common.max_number_of_printable_colours+=500;
new_storage=realloc(common.printable_colour, sizeof(struct colour_struct)*common.max_number_of_printable_colours);
if (new_storage) {
  common.printable_colour=new_storage;
  return TRUE;
  }
else {
  if (common.printable_colour) {
    free(common.printable_colour);
    }
  return FALSE;
  }
}
/* Colour enumeration:

   Go through every basic colour. Generate a colour for each
   passed combination at beginning except on top level
   because the pure basic colours have been generate already
   to keep certain special group mask information.

   At the actual level don't process basic colours bigger
   or same than the actual catridge in the level before.
   This grants that a combination of basic colours
   does occur once.

   Black must be mixed with Black only and any other
   colour must not be mixed together with Black.
   Also it is not possible to mix intensities of the
   same colour. Therefore a pattern is passed containing
   a bit set for each catridge used until now. So
   it can be changed by a simple AND operation whether
   the cartridge of the actual colour has been already
   used.

   Initialisation:
   Cyan, Magenta, Yellow 0
   group mask 0,
   cartridge pattern 0,
   printer pattern 0,
   no_of_basic_colour 0,
   max_basic_colour number_of_basic_colours */
int enumerate_colours(unsigned long cartridge_pattern,
                      unsigned long group_mask,
                      unsigned long printer_pattern,
                      int number_of_used_cartridges,
                      long cmy_component_cyan,
                      long cmy_component_magenta,
                      long cmy_component_yellow,
                      int max_basic_colour)
{
int actual_basic_colour;

if (number_of_used_cartridges > 1) {
  if (!check_colour_storage()) {
    return FALSE;
    }
  /* Store passed components */
  common.printable_colour[common.number_of_printable_colours].group_mask=group_mask;
  common.printable_colour[common.number_of_printable_colours].printer_pattern=printer_pattern;
  common.printable_colour[common.number_of_printable_colours].number_of_used_cartridges=number_of_used_cartridges;
  common.printable_colour[common.number_of_printable_colours].rgb_components[0]=cmy_component_cyan;
  common.printable_colour[common.number_of_printable_colours].rgb_components[1]=cmy_component_magenta;
  common.printable_colour[common.number_of_printable_colours].rgb_components[2]=cmy_component_yellow;
  /* Subtractive to additive colour converting is done
     later because information from all colours is needed. */
  common.number_of_printable_colours++;
  }
/* Exclude paper colour */
actual_basic_colour=1;
while (actual_basic_colour < max_basic_colour) {
  /* Black group must be only mixed with black */
  if (/* Each colour allowed at top level */
      (number_of_used_cartridges == 0) ||
       /* Never a colour from a cartridge already used */
      (((cartridge_pattern & (1<<common.basic_colour[actual_basic_colour].cartridge)) == 0) &&
         /* Black with Black */
       ((((group_mask & COLOUR_GROUP_BLACK_GROUP) != 0) &&
         ((common.basic_colour[actual_basic_colour].group_mask & COLOUR_GROUP_BLACK_GROUP) != 0)) ||
         /* Non Black with non Black */
        (((group_mask & COLOUR_GROUP_BLACK_GROUP) == 0) &&
         ((common.basic_colour[actual_basic_colour].group_mask & COLOUR_GROUP_BLACK_GROUP) == 0))))) {
    if (!enumerate_colours((cartridge_pattern | (1<<common.basic_colour[actual_basic_colour].cartridge)),
                           (group_mask | common.basic_colour[actual_basic_colour].group_mask) & COLOUR_GROUP_COMPONENT_MASK,
                           (printer_pattern | common.basic_colour[actual_basic_colour].printer_pattern),
                           number_of_used_cartridges + 1,
                           /* Note that basic colours are additive but result is subtractive */
                           (cmy_component_cyan + MAX_RGB_COMPONENT_VALUE - common.basic_colour[actual_basic_colour].rgb_components[0]),
                           (cmy_component_magenta + MAX_RGB_COMPONENT_VALUE - common.basic_colour[actual_basic_colour].rgb_components[1]),
                           (cmy_component_yellow + MAX_RGB_COMPONENT_VALUE - common.basic_colour[actual_basic_colour].rgb_components[2]),
                           actual_basic_colour)) {
      return FALSE;
      }
    }
  actual_basic_colour++;
  }
return TRUE;
}

int check_in_range(long base_value,
                   long second_value,
                   long compare_value)
{

if (base_value < second_value) {
  if ((base_value <= compare_value) &&
      (compare_value <= second_value)) return TRUE;
  }
else {
  if ((second_value <= compare_value) &&
      (compare_value <= base_value)) return TRUE;
  }
return FALSE;
}

int is_more_distant(int kind_of_compare,
                    long best_value,
                    long compare_value)
{

if (kind_of_compare == 0) {
  if (compare_value >= best_value) return FALSE;
  }
else {
  if (compare_value <= best_value) return FALSE;
  }
return TRUE;
}

long get_most_distant_value(int kind_of_value)
{

if (kind_of_value == 0) {
  return MIN_RGB_COMPONENT_VALUE;
  }
else {
  return MAX_RGB_COMPONENT_VALUE;
  }
}

int calculate_colour_ranges(void)
{
int i, j;
int result_flag;
int i_component;
int actual_colour;
int i_colour[3];
unsigned long group_selection_mask;
/* Dimensions determining cubes by axis:

   1 - Red
   2 - Green
   3 - Blue

   Index value 0 means smaller than central point.
   Index value 1 means bigger than central point. */
struct {
/* one for each axe */
long nearest_value[3];
int valid;
} best_neighbour[2][2][2];
struct colour_struct *nearest_colour[3];
struct {
long nearest_value;
int valid;
} component_distance[3][2];
long most_distant_value[3], new_most_distant_value;

/* Get the range for the colours */
/* Range determination is much more complicated then it looks on first view.

   Each point into the colour except the exact colours theirselves should be
   covered by at least two ranges for interpolation purposes.

   The simplest way would be to set this range for all colour from MIN_RGB_COMPONENT_VALUE
   to MAX_RGB_COMPONENT_VALUE but this not very helpful.

   Beside a colour there are eigth cubes. Inside the file you could represent
   each of this cubes as separate range. However this program is choosing another
   way. Each colour is represented exactly once with the Min/Max-Range of each
   colour compoment.

   Be aware of dividing the space into these eight cubes and determining
   the nearest neighbour colour to the actual colour and calculating
   the range from these eight neighbours. There some special cases which
   are leading to wrong results.

   So the following concept has been choosen (there are others way too).
   Each cube is checked against each colour except the actual one.
   If a colour is located inside that cube it is
   checked whether a component value of it is smaller than the
   actual one of the cube. If this is the case each smaller
   component value is updated separately and with it the
   according colour is stored. After all colours have been
   checked against the cube new maximal extensions for the
   cube are calculated from the maximal values of the
   colours related to the best component values. At the end
   the range around a colour is determined by calculating
   the maximum of the best component values of all the cubes
   of the colour. */
for (actual_colour=0; actual_colour < common.number_of_printable_colours; actual_colour++) {
  /* For Black-Mode the related colours must be compared against colours of their own only.
     Each other colour must be compared against all other possible colours (including Black). */
  if (common.black_mode_flag &&
      (((common.printable_colour[actual_colour].group_mask & COLOUR_GROUP_PAPER_COLOUR) != 0) ||
       ((common.printable_colour[actual_colour].group_mask & COLOUR_GROUP_BLACK_GROUP) != 0))) {
    group_selection_mask=COLOUR_GROUP_BLACK_MODE;
    }
  else {
    group_selection_mask=COLOUR_GROUP_ALL_COLOURS;
    }
  for (i_component=0; i_component < 3; i_component++) {
    for (i=0; i < 2; i++) {
      component_distance[i_component][i].nearest_value=get_most_distant_value(i);
      component_distance[i_component][i].valid=FALSE;
      }
    }
  /* Check each cube of the colour */
  for (i_colour[0]=0; i_colour[0] < 2; i_colour[0]++) {
    for (i_colour[1]=0; i_colour[1] < 2; i_colour[1]++) {
      for (i_colour[2]=0; i_colour[2] < 2; i_colour[2]++) {
        best_neighbour[i_colour[0]][i_colour[1]][i_colour[2]].valid=TRUE;
        /* At Grey only cubes with axe indices identical White is included
           else there might be gaps! Of course White is only checked against Black
           if Black mode is available. */
        if ((group_selection_mask == COLOUR_GROUP_BLACK_MODE) &&
            ((i_colour[0] != i_colour[1]) ||
             (i_colour[1] != i_colour[2]))) {
          best_neighbour[i_colour[0]][i_colour[1]][i_colour[2]].valid=FALSE;
          }
        for (i_component=0; i_component < 3; i_component++) {
          nearest_colour[i_component]=NULL;
          most_distant_value[i_component]=get_most_distant_value(i_colour[i_component]);
          best_neighbour[i_colour[0]][i_colour[1]][i_colour[2]].nearest_value[i_component]=most_distant_value[i_component];
          /* Don't examine any cubes where one axe is leading out off allowed range */
          if (most_distant_value[i_component] == common.printable_colour[actual_colour].rgb_components[i_component]) {
            best_neighbour[i_colour[0]][i_colour[1]][i_colour[2]].valid=FALSE;
            }
          }
        if (best_neighbour[i_colour[0]][i_colour[1]][i_colour[2]].valid) {
          /* Loop over all colours */
          for (i=0; i < common.number_of_printable_colours; i++) {
            if ((i != actual_colour) &&
                ((common.printable_colour[i].group_mask & group_selection_mask) != 0)) {
              /* All components of the colour must be located inside the actual cube */
              if (check_in_range(common.printable_colour[actual_colour].rgb_components[0],
                                 most_distant_value[0],
                                 common.printable_colour[i].rgb_components[0]) &&
                  check_in_range(common.printable_colour[actual_colour].rgb_components[1],
                                 most_distant_value[1],
                                 common.printable_colour[i].rgb_components[1]) &&
                  check_in_range(common.printable_colour[actual_colour].rgb_components[2],
                                 most_distant_value[2],
                                 common.printable_colour[i].rgb_components[2])) {
                /* A component is stored if it is closer to the according component
                   of the actual colour. Note that the same value as the actual colour
                   is not allowed. The index is required to determine whether
                   smaller or bigger comparation is needed. Index of 0 means less,
                   index of 1 means bigger than actual colour component but the opposite
                   is used for nearest colour comparision. */
                for (i_component=0; i_component < 3; i_component++) {
                  /* Ignore colours located on the same level like
                     the base colour. They would lead to wrong results.
                     They are only influencing one compomponent directly */
                  if (common.printable_colour[i].rgb_components[i_component] != common.printable_colour[actual_colour].rgb_components[i_component]) {
                    /* Check for colours influencing one component directly.
                       This is the case if the required component has a different
                       value and the both other components are the same as
                       the base colour */
                    result_flag=FALSE;
                    for (j=0; j < 3; j++) {
                      if (i_component != j) {
                        if (common.printable_colour[i].rgb_components[j] != common.printable_colour[actual_colour].rgb_components[j]) {
                          result_flag=TRUE;
                          }
                        }
                      }
                    if (result_flag) {
                      /* regular convex hull edge check */
                      if (!nearest_colour[i_component]) {
                        /* every colour is better than no colour */
                        nearest_colour[i_component]=&common.printable_colour[i];
                        best_neighbour[i_colour[0]][i_colour[1]][i_colour[2]].nearest_value[i_component]=common.printable_colour[i].rgb_components[i_component];
                        }
                      else {
                        /* Decision whether the axe is going to
                           or from the base colour */
                        if (i_colour[i_component] == 0) {
                          if (best_neighbour[i_colour[0]][i_colour[1]][i_colour[2]].nearest_value[i_component] < common.printable_colour[i].rgb_components[i_component]) {
                            /* New colour is closer to base colour at that component
                               than old colour */
                            nearest_colour[i_component]=&common.printable_colour[i];
                            best_neighbour[i_colour[0]][i_colour[1]][i_colour[2]].nearest_value[i_component]=common.printable_colour[i].rgb_components[i_component];
                            }
                          else if (best_neighbour[i_colour[0]][i_colour[1]][i_colour[2]].nearest_value[i_component] == common.printable_colour[i].rgb_components[i_component]) {
                            /* New and old colour are having same distance at that component
                               to base colour. Check the other components accordign direction
                               of other axis */
                            result_flag=TRUE;
                            for (j=0; j < 3; j++) {
                              if (i_component != j) {
                                if (i_colour[j] == 0) {
                                  if (nearest_colour[i_component]->rgb_components[j] > common.printable_colour[i].rgb_components[j]) {
                                    result_flag=FALSE;
                                    }
                                  }
                                else {
                                  if (nearest_colour[i_component]->rgb_components[j] < common.printable_colour[i].rgb_components[j]) {
                                    result_flag=FALSE;
                                    }
                                  }
                                }
                              }
                            if (result_flag) {
                              nearest_colour[i_component]=&common.printable_colour[i];
                              best_neighbour[i_colour[0]][i_colour[1]][i_colour[2]].nearest_value[i_component]=common.printable_colour[i].rgb_components[i_component];
                              }
                            }
                          }
                        else {
                          if (best_neighbour[i_colour[0]][i_colour[1]][i_colour[2]].nearest_value[i_component] > common.printable_colour[i].rgb_components[i_component]) {
                            /* New colour is closer to base colour at that component
                               than old colour */
                            nearest_colour[i_component]=&common.printable_colour[i];
                            best_neighbour[i_colour[0]][i_colour[1]][i_colour[2]].nearest_value[i_component]=common.printable_colour[i].rgb_components[i_component];
                            }
                          else if (best_neighbour[i_colour[0]][i_colour[1]][i_colour[2]].nearest_value[i_component] == common.printable_colour[i].rgb_components[i_component]) {
                            /* New and old colour are having same distance at that component
                               to base colour. Check the other components accordign direction
                               of other axis */
                            result_flag=TRUE;
                            for (j=0; j < 3; j++) {
                              if (i_component != j) {
                                if (i_colour[j] == 0) {
                                  if (nearest_colour[i_component]->rgb_components[j] < common.printable_colour[i].rgb_components[j]) {
                                    result_flag=FALSE;
                                    }
                                  }
                                else {
                                  if (nearest_colour[i_component]->rgb_components[j] > common.printable_colour[i].rgb_components[j]) {
                                    result_flag=FALSE;
                                    }
                                  }
                                }
                              }
                            if (result_flag) {
                              nearest_colour[i_component]=&common.printable_colour[i];
                              best_neighbour[i_colour[0]][i_colour[1]][i_colour[2]].nearest_value[i_component]=common.printable_colour[i].rgb_components[i_component];
                              }
                            }
                          }
                        }
                      }
                    else {
                      /* Check for improved axe component */
                      if (!component_distance[i_component][i_colour[i_component]].valid) {
                        component_distance[i_component][i_colour[i_component]].nearest_value=common.printable_colour[i].rgb_components[i_component];
                        component_distance[i_component][i_colour[i_component]].valid=TRUE;
                        }
                      else {
                        if (i_colour[i_component] == 0) {
                          if (component_distance[i_component][i_colour[i_component]].nearest_value < common.printable_colour[i].rgb_components[i_component]) {
                            component_distance[i_component][i_colour[i_component]].nearest_value=common.printable_colour[i].rgb_components[i_component];
                            }
                          }
                        else {
                          if (component_distance[i_component][i_colour[i_component]].nearest_value > common.printable_colour[i].rgb_components[i_component]) {
                            component_distance[i_component][i_colour[i_component]].nearest_value=common.printable_colour[i].rgb_components[i_component];
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          /* For each color component get maximum from each
             cube axe */
          for (i_component=0; i_component < 3; i_component++) {
            new_most_distant_value=common.printable_colour[actual_colour].rgb_components[i_component];
            /* go through the cube axis */
            for (i=0; i < 3; i++) {
              if (nearest_colour[i]) {
                if (is_more_distant(i_colour[i_component],
                                    new_most_distant_value,
                                    nearest_colour[i]->rgb_components[i_component])) {
                  new_most_distant_value=nearest_colour[i]->rgb_components[i_component];
                  }
                }
              else {
                if (i == i_component) {
                  new_most_distant_value=most_distant_value[i_component];
                  }
                }
              }
            best_neighbour[i_colour[0]][i_colour[1]][i_colour[2]].nearest_value[i_component]=new_most_distant_value;
            }
          }
        }
      }
    }
  /* Extension of all cubes determined.
     Get most distant values for each component from all cubes
     to determine colour range. */
  for (i_component=0; i_component < 3; i_component++) {
    common.printable_colour[actual_colour].rgb_range_min[i_component]=common.printable_colour[actual_colour].rgb_components[i_component];
    common.printable_colour[actual_colour].rgb_range_max[i_component]=common.printable_colour[actual_colour].rgb_components[i_component];
    for (i_colour[0]=0; i_colour[0] < 2; i_colour[0]++) {
      for (i_colour[1]=0; i_colour[1] < 2; i_colour[1]++) {
        for (i_colour[2]=0; i_colour[2] < 2; i_colour[2]++) {
          if (best_neighbour[i_colour[0]][i_colour[1]][i_colour[2]].valid) {
            if (i_colour[i_component] == 0) {
              if (is_more_distant(i_colour[i_component],
                                  common.printable_colour[actual_colour].rgb_range_min[i_component],
                                  best_neighbour[i_colour[0]][i_colour[1]][i_colour[2]].nearest_value[i_component])) {
                common.printable_colour[actual_colour].rgb_range_min[i_component]=best_neighbour[i_colour[0]][i_colour[1]][i_colour[2]].nearest_value[i_component];
                }
              }
            else {
              if (is_more_distant(i_colour[i_component],
                                  common.printable_colour[actual_colour].rgb_range_max[i_component],
                                  best_neighbour[i_colour[0]][i_colour[1]][i_colour[2]].nearest_value[i_component])) {
                common.printable_colour[actual_colour].rgb_range_max[i_component]=best_neighbour[i_colour[0]][i_colour[1]][i_colour[2]].nearest_value[i_component];
                }
              }
            }
          }
        }
      }
    /* If a value for the according axe is given then take axe value. */
    for (i=0; i < 2; i++) {
      if (component_distance[i_component][i].valid) {
        if (i == 0) {
          common.printable_colour[actual_colour].rgb_range_min[i_component]=component_distance[i_component][i].nearest_value;
          }
        else {
          common.printable_colour[actual_colour].rgb_range_max[i_component]=component_distance[i_component][i].nearest_value;
          }
        }
      else {
        /* Check for colour spaces edges without axe values.
           Colour is on an edge of colour space. But the
           checked axe value must not be in the middle of the possible
           values else there is an approximation possibility by the
           cubes. However if there is a value direct on the
           axe this is taken instead of minimum/maximum.
           but not in black mode. */
        if (group_selection_mask == COLOUR_GROUP_ALL_COLOURS) {
          result_flag=TRUE;
          for (j=0; j < 3; j++) {
            if (j != i_component) {
              if ((MIN_RGB_COMPONENT_VALUE < common.printable_colour[actual_colour].rgb_components[j]) &&
                  (common.printable_colour[actual_colour].rgb_components[j]) < MAX_RGB_COMPONENT_VALUE) {
                result_flag=FALSE;
                }
              }
            }
          if (result_flag) {
            if (i == 0) {
              common.printable_colour[actual_colour].rgb_range_min[i_component]=get_most_distant_value(i);
              }
            else {
              common.printable_colour[actual_colour].rgb_range_max[i_component]=get_most_distant_value(i);
              }
            }
          }
        }
      }
    }
  }
return TRUE;
}

int import_extern_calibration(void)
{
unsigned long group_mask_union;
char file_line[512];
FILE *extern_calibration_file;

if ((extern_calibration_file=fopen(common.extern_calibration_file_name,
                                   "r")) == NULL) {
  return FALSE;
  }
group_mask_union=0;
while (!feof(extern_calibration_file)) {
  if (fgets(file_line,
            511,
            extern_calibration_file)) {
    if (sscanf(file_line,
               "%ld %ld %ld %lx %lx %ld",
               &common.printable_colour[common.number_of_printable_colours].rgb_components[0],
               &common.printable_colour[common.number_of_printable_colours].rgb_components[1],
               &common.printable_colour[common.number_of_printable_colours].rgb_components[2],
               &common.printable_colour[common.number_of_printable_colours].printer_pattern,
               &common.printable_colour[common.number_of_printable_colours].group_mask,
               &common.printable_colour[common.number_of_printable_colours].paper_colour_fraction) == 6) {
      common.printable_colour[common.number_of_printable_colours].number_of_used_cartridges=0;
      group_mask_union|=common.printable_colour[common.number_of_printable_colours].group_mask;
      common.number_of_printable_colours++;
      }
    }
  }
fclose(extern_calibration_file);
if ((group_mask_union & COLOUR_GROUP_BLACK_GROUP) != 0) {
  common.black_mode_flag=TRUE;
  }
return TRUE;
}

int build_print_colours(int mix_flag,
                        char *import_file_name)
{
int i, j;
int result_flag;
int i_component;
int actual_colour;
double factor;

common.printable_colour=NULL;
common.number_of_printable_colours=0;
common.max_number_of_printable_colours=0;
/* Build all colours */
/* Build all no mix colours */
for (actual_colour=0; actual_colour < common.number_of_basic_colours; actual_colour++) {
  if (!check_colour_storage()) {
    return FALSE;
    }
  common.printable_colour[common.number_of_printable_colours].group_mask=common.basic_colour[actual_colour].group_mask;
  common.printable_colour[common.number_of_printable_colours].printer_pattern=common.basic_colour[actual_colour].printer_pattern;
  if (actual_colour == 0) {
    common.printable_colour[common.number_of_printable_colours].number_of_used_cartridges=0;
    }
  else {
    common.printable_colour[common.number_of_printable_colours].number_of_used_cartridges=1;
    }
  /* Generate as subtractive because of later retranslation */
  common.printable_colour[common.number_of_printable_colours].rgb_components[0]=MAX_RGB_COMPONENT_VALUE - common.basic_colour[actual_colour].rgb_components[0];
  common.printable_colour[common.number_of_printable_colours].rgb_components[1]=MAX_RGB_COMPONENT_VALUE - common.basic_colour[actual_colour].rgb_components[1];
  common.printable_colour[common.number_of_printable_colours].rgb_components[2]=MAX_RGB_COMPONENT_VALUE - common.basic_colour[actual_colour].rgb_components[2];
  common.number_of_printable_colours++;
  }
/* Build all mixed colours

   All combinations must be enumerated. But duplicated numbers
   must be avoided. Loop over all basic colours except paper colour.
   Build subloops over the same range but only up to the
   actual colour for every catridge. Mixtures of colours
   of same catridges are forbidden.

   At Black colours can be only mixed with other black catridges. */
if (mix_flag) {
  if (!enumerate_colours(0,
                         0,
                         0,
                         0,
                         0,
                         0,
                         0,
                         common.number_of_basic_colours)) {
    return FALSE;
    }
  }
/* Subtractive to additive */
/* Include Paper colour */
for (actual_colour=0; actual_colour < common.number_of_printable_colours; actual_colour++) {
  result_flag=FALSE;
  for (i_component=0; i_component < 3; i_component++) {
    /* Exclude Paper colour */
    if (actual_colour > 0) {
      /* Reduce values according given factor to allow very light prints.

         This is done by increasing CMY-values. If points are falling out of the cube this
         is corrected afterwards by including an amount of paper colour.

         A logical problem is pure Black. Their might be several Grey scales.
         Logically in a picture pure Black should be replaced by a grey and paper colour if
         the colours are enlighten. However then there is no speed up for Text and the text
         will also appear as Grey. So keep pure Black here even this might lead to a jump
         inside Pictures under certain circumstances. */
      common.printable_colour[actual_colour].rgb_components[i_component]=(common.printable_colour[actual_colour].rgb_components[i_component]*common.intensity_reduction)/100;
      }
    if ((common.printable_colour[actual_colour].rgb_components[i_component]=MAX_RGB_COMPONENT_VALUE - common.printable_colour[actual_colour].rgb_components[i_component]) < 0) {
      /* too dark in overlay of subtraction colours */
      result_flag=TRUE;
      }
    }
  if (result_flag) {
    /* Construct line between point and paper colour:

       Px,y,z is the colour point outside the colour cube
       PCx,y,z is the paper colour point inside the colour cube

       each the line can be described as

       Lx,y,z=F*(PCx,y,z - Px,y,z) + Px,y,z with 0 <= F <= 1

       Lx=0 or Ly=0 or Lz=0 describes the point where the line enters
       the cube and the other two coordinates are located on a side
       of the colour cube.

       it is

       0=F*(PCx - Px) + Px

       calculate F and using this the other two remaing coordinates.
       If one of the coordinates is not inside colour cube so try y
       and afterwards z coordinate equation.

       F=-Px/(PCx - Px) which must be ignored in case of PCx=Px */
    i=0;
    /* Same as paper colour cant occur logically at this point.
       So no endless loop is possible. */
    while(result_flag) {
      if (common.printable_colour[0].rgb_components[i] != common.printable_colour[actual_colour].rgb_components[i]) {
        factor=(double) -common.printable_colour[actual_colour].rgb_components[i]/(common.printable_colour[0].rgb_components[i] - common.printable_colour[actual_colour].rgb_components[i]);
        result_flag=FALSE;
        for (i_component=0; i_component < 3; i_component++) {
          j=factor*(common.printable_colour[0].rgb_components[i_component] - common.printable_colour[actual_colour].rgb_components[i_component]) + common.printable_colour[actual_colour].rgb_components[i_component];
          if ((j < 0) ||
              (j > 255)) {
            /* One component out of range. */
            result_flag=TRUE;
            }
          }
        }
      i++;
      }
    /* Update colour coordinates */
    for (i_component=0; i_component < 3; i_component++) {
      common.printable_colour[actual_colour].rgb_components[i_component]=factor*(common.printable_colour[0].rgb_components[i_component] - common.printable_colour[actual_colour].rgb_components[i_component]) + common.printable_colour[actual_colour].rgb_components[i_component];
      if ((j < 0) ||
          (j > 255)) {
        /* One component out of range. */
        result_flag=TRUE;
        }
      }
    common.printable_colour[actual_colour].paper_colour_fraction=factor*100;
    }
  else {
    common.printable_colour[actual_colour].paper_colour_fraction=0;
    }
  }
/* Import additional files from file if given */
if (import_file_name &&
    (strlen(import_file_name) > 0)) {
  import_extern_calibration();
  }
/* Throw out unnecassary colours */
/* Exclude Paper colour */
actual_colour=1;
while (actual_colour < common.number_of_printable_colours) {
  if (common.printable_colour[actual_colour].paper_colour_fraction == 100) {
    /* replace the unecassary colour by the last colour inside the list */
    common.number_of_printable_colours--;
    common.printable_colour[actual_colour].group_mask=common.printable_colour[common.number_of_printable_colours].group_mask;
    common.printable_colour[actual_colour].printer_pattern=common.printable_colour[common.number_of_printable_colours].printer_pattern;
    common.printable_colour[actual_colour].number_of_used_cartridges=common.printable_colour[common.number_of_printable_colours].number_of_used_cartridges;
    common.printable_colour[actual_colour].rgb_components[0]=common.printable_colour[common.number_of_printable_colours].rgb_components[0];
    common.printable_colour[actual_colour].rgb_components[1]=common.printable_colour[common.number_of_printable_colours].rgb_components[1];
    common.printable_colour[actual_colour].rgb_components[2]=common.printable_colour[common.number_of_printable_colours].rgb_components[2];
    common.printable_colour[actual_colour].paper_colour_fraction=common.printable_colour[common.number_of_printable_colours].paper_colour_fraction;
    }
  else {
    actual_colour++;
    }
  }
/* Delete Duplicates. That combination is preferred which is using
   the smallest number of cartridges. */
actual_colour=0;
while (actual_colour < common.number_of_printable_colours) {
  i=actual_colour + 1;
  while (i < common.number_of_printable_colours) {
    if ((common.printable_colour[actual_colour].rgb_components[0] == common.printable_colour[i].rgb_components[0]) &&
        (common.printable_colour[actual_colour].rgb_components[1] == common.printable_colour[i].rgb_components[1]) &&
        (common.printable_colour[actual_colour].rgb_components[2] == common.printable_colour[i].rgb_components[2])) {
      /* If colour to check uses fewer catridges than put it to actual colour */
      if (common.printable_colour[actual_colour].number_of_used_cartridges > common.printable_colour[i].number_of_used_cartridges) {
        common.printable_colour[actual_colour].group_mask=common.printable_colour[i].group_mask;
        common.printable_colour[actual_colour].printer_pattern=common.printable_colour[i].printer_pattern;
        common.printable_colour[actual_colour].number_of_used_cartridges=common.printable_colour[i].number_of_used_cartridges;
        common.printable_colour[actual_colour].paper_colour_fraction=common.printable_colour[i].paper_colour_fraction;
        }
      /* replace the doubled colour by the last colour inside the list */
      common.number_of_printable_colours--;
      common.printable_colour[i].group_mask=common.printable_colour[common.number_of_printable_colours].group_mask;
      common.printable_colour[i].printer_pattern=common.printable_colour[common.number_of_printable_colours].printer_pattern;
      common.printable_colour[i].number_of_used_cartridges=common.printable_colour[common.number_of_printable_colours].number_of_used_cartridges;
      common.printable_colour[i].rgb_components[0]=common.printable_colour[common.number_of_printable_colours].rgb_components[0];
      common.printable_colour[i].rgb_components[1]=common.printable_colour[common.number_of_printable_colours].rgb_components[1];
      common.printable_colour[i].rgb_components[2]=common.printable_colour[common.number_of_printable_colours].rgb_components[2];
      common.printable_colour[i].paper_colour_fraction=common.printable_colour[common.number_of_printable_colours].paper_colour_fraction;
      }
    else {
      i++;
      }
    }
  actual_colour++;
  }
/*Build colour ranges */
calculate_colour_ranges();
/* Modify the calibration file */
modify_calibration_file(mix_flag,
                        TRUE,
                        import_file_name);
if (common.printable_colour) {
  free(common.printable_colour);
  }
return TRUE;
}

int prepare_print(unsigned long colour_scheme)
{
FILE *draw_file;
int i, j, actual_colour;
struct {
int x_low;
int y_low;
int x_high;
int y_high;
} paper_bound_box;
struct {
int type;
int size;
int x_low;
int y_low;
int x_high;
int y_high;
int fill_colour;
int outline_colour;
int outline_width;
unsigned int style;
int edge_1_tag_identifier;
int edge_1_x;
int edge_1_y;
int edge_2_tag_identifier;
int edge_2_x;
int edge_2_y;
int edge_3_tag_identifier;
int edge_3_x;
int edge_3_y;
int edge_4_tag_identifier;
int edge_4_x;
int edge_4_y;
int close_tag_identifier;
int terminator_tag_identifer;
} object;
_kernel_swi_regs regs;

/* Generate Basic Colours */
if (!set_basic_colours(colour_scheme)) return FALSE;
/* Generate Drawfile:
   For each cartridge a row of rectangles is generated.
   There is one rectangle per each stage. */
if ((draw_file=fopen("<Wimp$ScrapDir>.PDPEICal.Pattern",
                     "wb")) == NULL) {
  return FALSE;
  }
/* Draw File header */
fprintf(draw_file,
        "Draw");
fputc(201, draw_file);
for (i=0; i<7; i++) {
  fputc(0, draw_file);
  }
fprintf(draw_file,
        "Draw        ");
paper_bound_box.x_low=35300;
paper_bound_box.y_low=36300;
paper_bound_box.x_high=paper_bound_box.x_low + 310000;
paper_bound_box.y_high=paper_bound_box.y_low + 490000;
fwrite(&paper_bound_box,
       sizeof paper_bound_box,
       1,
       draw_file);
object.type=2;
object.size=sizeof object;
object.outline_colour=-1;
object.outline_width=0;
object.style=0;
object.edge_1_tag_identifier=2;
object.edge_2_tag_identifier=8;
object.edge_3_tag_identifier=8;
object.edge_4_tag_identifier=8;
object.close_tag_identifier=5;
object.terminator_tag_identifer=0;
for (i=0; i < common.number_of_cartridges; i++) {
  object.y_low=paper_bound_box.y_high - (i + 1)*36300;
  j=0;
  actual_colour=-1;
  while(actual_colour < common.number_of_basic_colours) {
    actual_colour=find_next_cartridge_colour(i,
                                            actual_colour);
    if (actual_colour < common.number_of_basic_colours) {
      object.x_low=paper_bound_box.x_low + j*36300;
      object.x_high=object.x_low + SQUARE_SIDE_SIZE;
      object.y_high=object.y_low + SQUARE_SIDE_SIZE;
      object.edge_1_x=object.x_low;
      object.edge_1_y=object.y_low;
      object.edge_2_x=object.x_high;
      object.edge_2_y=object.y_low;
      object.edge_3_x=object.x_high;
      object.edge_3_y=object.y_high;
      object.edge_4_x=object.x_low;
      object.edge_4_y=object.y_high;
      object.fill_colour=common.basic_colour[actual_colour].rgb_components[0]<<8;
      object.fill_colour|=common.basic_colour[actual_colour].rgb_components[1]<<16;
      object.fill_colour|=common.basic_colour[actual_colour].rgb_components[2]<<24;
      fwrite(&object,
             sizeof object,
             1,
             draw_file);
      j++;
      }
    }
  }
fclose(draw_file);
regs.r[0]=18;
regs.r[1]=(int) "<Wimp$ScrapDir>.PDPEICal.Pattern";
regs.r[2]=0xAFF;
_kernel_swi(OS_File, &regs, &regs);
return TRUE;
}

/* ---------- General initialization and dropping --------- */
int initialize_application(void)
{

strcpy(common.printer_name, "");
common.basic_colour=NULL;
common.shutdown_flag=FALSE;
common.calibration_process_flag=FALSE;
return TRUE;
}

int drop_application(void)
{

if (common.basic_colour) {
  free(common.basic_colour);
  common.basic_colour=NULL;
  }
return TRUE;
}

/* ---------- Toolbox handling --------- */
int disable_set_calibration_file(ObjectId window)
{
unsigned int button_flags;
_kernel_oserror *error_os;

if ((error_os=gadget_get_flags(0,
                               window,
                               COMPONENT_START_CALIBRATION_FILE,
                               &button_flags)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
if ((error_os=gadget_set_flags(0,
                               window,
                               COMPONENT_START_CALIBRATION_FILE,
                               button_flags | Gadget_Faded)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
return TRUE;
}

int check_and_set_calibration_file(ObjectId window)
{
int size;
char command[500];
FILE *check_file;
_kernel_oserror *error_os;

size=499;
command[size]='\0';
if ((error_os=writablefield_get_value(0,
                                      window,
                                      COMPONENT_CALIBRATION_FILE,
                                      command,
                                      size,
                                      &size)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
if (strlen(command) == 0) {
  strcpy(common.calibration_file_name, command);
  sprintf(command,
          "<PDPEICal$ConfDir>.%s",
          common.printer_name);
  /* Remove of file will lead to usage of CalibDef later */
  remove(command);
  return TRUE;
  }
/* check whether file exists */
check_file=fopen(command, "r");
if (check_file) {
  fclose(check_file);
  strcpy(common.calibration_file_name, command);
  sprintf(command,
          "Copy %s <PDPEICal$ConfDir>.%s ~CF~N~V",
          common.calibration_file_name,
          common.printer_name);
  system(command);
  sprintf(common.calibration_file_name,
          "<PDPEICal$ConfDir>.%s",
          common.printer_name);
  if ((error_os=writablefield_set_value(0,
                                        window,
                                        COMPONENT_CALIBRATION_FILE,
                                        common.calibration_file_name)) != NULL) {
    wimp_report_error(error_os,
                      0,
                      APPLICATION_NAME,
                      0,
                      0,
                      0);
    drop_application();
    exit(EXIT_FAILURE);
    }
  disable_set_calibration_file(window);
  }
else {
  show_message(2);
  /* Restore old value */
  if ((error_os=writablefield_set_value(0,
                                        window,
                                        COMPONENT_CALIBRATION_FILE,
                                        common.calibration_file_name)) != NULL) {
    wimp_report_error(error_os,
                      0,
                      APPLICATION_NAME,
                      0,
                      0,
                      0);
    drop_application();
    exit(EXIT_FAILURE);
    }
  disable_set_calibration_file(window);
  return FALSE;
  }
return TRUE;
}

int update_calibration_list(ObjectId window)
{
char value_list[500];
int value_list_length;
char file_line[512];
int actual_calibration;
FILE *calibration_file;
_kernel_oserror *error_os;

if ((calibration_file=fopen(common.calibration_file_name,
                             "r")) == NULL) {
  return FALSE;
  }
strcpy(value_list, "");
while(!feof(calibration_file)) {
  if (fgets(file_line,
            511,
            calibration_file)) {
    if (strncmp(file_line,
                FILE_COLOUR_CALIBRATION_START,
                strlen(FILE_COLOUR_CALIBRATION_START)) == 0) {
      /* Determine number of calibration */
      actual_calibration=atol(&file_line[strlen(FILE_COLOUR_CALIBRATION_START)]);
      value_list_length=strlen(value_list);
      if (value_list_length == 0) {
        sprintf(&value_list[value_list_length],
                "%d",
                actual_calibration);
        }
      else {
        sprintf(&value_list[value_list_length],
                ",%d",
                actual_calibration);
        }
      }
    }
  }
fclose(calibration_file);
/* Set existing values for calibration accordingly */
if ((error_os=stringset_set_available(0,
                                      window,
                                      COMPONENT_CALIBRATION_NUMBER,
                                      value_list)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
return TRUE;
}

/* !!!!!!!!!! functions !!!!!!!!!! */
/* ---------- Application Handling --------- */
int program_quitT(int event_code, ToolboxEvent *event, IdBlock *id_block, void *client_handle)
{

common.shutdown_flag=TRUE;
return TRUE;
}

int colour_set_abort(int event_code, ToolboxEvent *event, IdBlock *id_block, void *client_handle)
{
char command[300];
_kernel_oserror *error_os;

/* Delete Colour Dialog when aborted */
if ((error_os=toolbox_delete_object(0,
                                    id_block->self_id)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
/* Restore Backup File */
sprintf(command,
        "Copy <PDPEICal$Dir>.Resources.Calibs.Backup <PDPEICal$ConfDir>.%s ~CDF~N~V",
        common.printer_name);
system(command);
common.calibration_process_flag=FALSE;
/* Clean up */
if (common.basic_colour) {
  free(common.basic_colour);
  common.basic_colour=NULL;
  }
return TRUE;
}

int set_colour(int event_code, ToolboxEvent *event, IdBlock *id_block, void *client_handle)
{
_kernel_oserror *error_os;
struct {
int colour;
int size;
int colour_model;
} colour_block;

colour_block.colour=common.basic_colour[common.actual_colour].rgb_components[0]<<8;
colour_block.colour|=common.basic_colour[common.actual_colour].rgb_components[1]<<16;
colour_block.colour|=common.basic_colour[common.actual_colour].rgb_components[2]<<24;
colour_block.size=0;
colour_block.colour_model=0;
if ((error_os=colourdbox_set_colour(0,
                                    id_block->self_id,
                                    (int *) &colour_block)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
/* Must be located here because other location would cause trouble with cancel if ok is clicked */
if ((error_os=event_register_toolbox_handler(id_block->self_id,
                                             ColourDbox_DialogueCompleted,
                                             colour_set_abort,
                                             NULL)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
return TRUE;
}

int check_colour(int event_code, ToolboxEvent *event, IdBlock *id_block, void *client_handle)
{
_kernel_swi_regs regs;
_kernel_oserror *error_os;
ColourDboxColourSelectedEvent *cdb_event;

/* Deregister Cancel handler to avoid trouble */
if ((error_os=event_deregister_toolbox_handler(id_block->self_id,
                                               ColourDbox_DialogueCompleted,
                                               colour_set_abort,
                                               NULL)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
/* Store corrected colour */
cdb_event=(ColourDboxColourSelectedEvent *) event;
common.basic_colour[common.actual_colour].rgb_components[0]=(cdb_event->colour_block[0]>>8) & MAX_RGB_COMPONENT_VALUE;
common.basic_colour[common.actual_colour].rgb_components[1]=(cdb_event->colour_block[0]>>16) & MAX_RGB_COMPONENT_VALUE;
common.basic_colour[common.actual_colour].rgb_components[2]=(cdb_event->colour_block[0]>>24) & MAX_RGB_COMPONENT_VALUE;
common.actual_colour=find_next_cartridge_colour(common.actual_cartridge,
                                                common.actual_colour);
common.actual_column++;
if (common.actual_colour >= common.number_of_basic_colours) {
  common.actual_cartridge++;
  common.actual_column=1;
  if (common.actual_cartridge < common.number_of_cartridges) {
    common.actual_colour=find_next_cartridge_colour(common.actual_cartridge,
                                                   -1);
    }
  }
if (common.actual_cartridge < common.number_of_cartridges) {
  /* Show next colour */
  if ((error_os=toolbox_show_object(0,
                                    id_block->self_id,
                                    0,
                                    NULL,
                                    0,
                                    0)) != NULL) {
    wimp_report_error(error_os,
                      0,
                      APPLICATION_NAME,
                      0,
                      0,
                      0);
    drop_application();
    exit(EXIT_FAILURE);
    }
  }
else {
  /* Delete Colour Dialog at end */
  if ((error_os=toolbox_delete_object(0,
                                      id_block->self_id)) != NULL) {
    wimp_report_error(error_os,
                      0,
                      APPLICATION_NAME,
                      0,
                      0,
                      0);
    drop_application();
    exit(EXIT_FAILURE);
    }
  /* Generate the final data file */
  _kernel_swi(Hourglass_On, &regs, &regs);
  build_print_colours(TRUE,
                      common.extern_calibration_file_name);
  _kernel_swi(Hourglass_Off, &regs, &regs);
  common.calibration_process_flag=FALSE;
  /* Clean up */
  if (common.basic_colour) {
    free(common.basic_colour);
    common.basic_colour=NULL;
    }
  }
return TRUE;
}

int drag_calibration_file_name(WimpMessage *message, void *handle)
{
ObjectId object;
ComponentId component;
_kernel_oserror *error_os;

/* Determine the field in which the file name is filled */
if ((error_os=window_wimp_to_toolbox(0,
                                     message->data.data_load.destination_window,
                                     message->data.data_load.destination_icon,
                                     &object,
                                     &component)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
if (object != common.window) {
  /* ignore */
  return TRUE;
  }
if (component == COMPONENT_COLOUR_DEFINITION_FILE) {
  if ((error_os=writablefield_set_value(0,
                                        common.window,
                                        COMPONENT_COLOUR_DEFINITION_FILE,
                                        message->data.data_load.leaf_name)) != NULL) {
    wimp_report_error(error_os,
                      0,
                      APPLICATION_NAME,
                      0,
                      0,
                      0);
    drop_application();
    exit(EXIT_FAILURE);
    }
  }
else {
  unsigned int button_flags;

  if ((error_os=writablefield_set_value(0,
                                        common.window,
                                        COMPONENT_CALIBRATION_FILE,
                                        message->data.data_load.leaf_name)) != NULL) {
    wimp_report_error(error_os,
                      0,
                      APPLICATION_NAME,
                      0,
                      0,
                      0);
    drop_application();
    exit(EXIT_FAILURE);
    }
  /* Needed because Toolbox events are delayed until Cursor moves */
  if ((error_os=gadget_get_flags(0,
                                 common.window,
                                 COMPONENT_START_CALIBRATION_FILE,
                                 &button_flags)) != NULL) {
    wimp_report_error(error_os,
                      0,
                      APPLICATION_NAME,
                      0,
                      0,
                      0);
    drop_application();
    exit(EXIT_FAILURE);
    }
  if ((button_flags & Gadget_Faded) != 0) {
    if ((error_os=gadget_set_flags(0,
                                   common.window,
                                   COMPONENT_START_CALIBRATION_FILE,
                                   button_flags & (~Gadget_Faded))) != NULL) {
      wimp_report_error(error_os,
                        0,
                        APPLICATION_NAME,
                        0,
                        0,
                        0);
      drop_application();
      exit(EXIT_FAILURE);
      }
    }
  }
return TRUE;
}

int stop_calibration(int event_code, ToolboxEvent *event, IdBlock *id_block, void *client_handle)
{
_kernel_oserror *error_os;

if ((error_os=event_deregister_message_handler(Wimp_MDataLoad,
                                               drag_calibration_file_name,
                                               0)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
if ((error_os=toolbox_delete_object(0,
                                    id_block->self_id)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
common.calibration_process_flag=FALSE;
return TRUE;
}

int start_calibration(int event_code, ToolboxEvent *event, IdBlock *id_block, void *client_handle)
{
char h[20];
int i;
int size;
int button_state;
unsigned int button_flags;
_kernel_oserror *error_os;

/* Check whether calibration file has been changed */
if ((error_os=gadget_get_flags(0,
                               id_block->self_id,
                               COMPONENT_START_CALIBRATION_FILE,
                               &button_flags)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
if ((button_flags & Gadget_Faded) == 0) {
  check_and_set_calibration_file(id_block->self_id);
  }
/* Evaluate the dialog settings */
/* Get calibration number */
if ((error_os=stringset_get_selected(0,
                                     id_block->self_id,
                                     COMPONENT_CALIBRATION_NUMBER,
                                     h,
                                     19,
                                     &i)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
h[19]='\0';
common.calibration=atol(h);
/* Determine the used cartridges */
common.colour_scheme=0;
for (i=0; i < 13; i++) {
  if ((error_os=optionbutton_get_state(0,
                                       id_block->self_id,
                                       i + COMPONENT_COLOR_SELECTION,
                                       &button_state)) != NULL) {
    wimp_report_error(error_os,
                      0,
                      APPLICATION_NAME,
                      0,
                      0,
                      0);
    drop_application();
    exit(EXIT_FAILURE);
    }
  if (button_state == 1) {
    common.colour_scheme|=1<<i;
    }
  }
/* Get number of bits per pixel */
if ((error_os=stringset_get_selected(0,
                                     id_block->self_id,
                                     COMPONENT_BITS_PER_PIXEL,
                                     h,
                                     19,
                                     &i)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
h[19]='\0';
common.bits_per_pixel=atoi(h);
/* Get number of pixel pad bits */
if ((error_os=stringset_get_selected(0,
                                     id_block->self_id,
                                     COMPONENT_PIXEL_PAD_BITS,
                                     h,
                                     19,
                                     &i)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
h[19]='\0';
common.pixel_pad_bits=atoi(h);
if (common.pixel_pad_bits < 0) {
  common.shift_pixel_pad_bits=-common.pixel_pad_bits;
  }
else {
  common.shift_pixel_pad_bits=0;
  }
/* Get intensity mode */
common.intensity_mode=0;
if ((error_os=stringset_get_selected(1,
                                     id_block->self_id,
                                     COMPONENT_INTENSITY_MODE,
                                     &i)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
if ((0 <= i) &&
    (i <= 1)) {
  common.intensity_mode=i;
  }
/* Get intensity reduction value */
common.intensity_reduction=100;
if ((error_os=numberrange_get_value(0,
                                    id_block->self_id,
                                    COMPONENT_INTENSITY_REDUCTION,
                                    (int *) &common.intensity_reduction)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
/* Get external calibration file info */
size=499;
common.extern_calibration_file_name[size]='\0';
if ((error_os=writablefield_get_value(0,
                                      id_block->self_id,
                                      COMPONENT_COLOUR_DEFINITION_FILE,
                                      common.extern_calibration_file_name,
                                      size,
                                      &size)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
/* Calibration window no longer needed */
if ((error_os=event_deregister_toolbox_handler(id_block->self_id,
                                               Window_HasBeenHidden,
                                               stop_calibration,
                                               NULL)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
if ((error_os=event_deregister_message_handler(Wimp_MDataLoad,
                                               drag_calibration_file_name,
                                               0)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
if ((error_os=toolbox_delete_object(0,
                                    id_block->self_id)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
if (common.pixel_pad_bits >= 0) {
  common.number_of_intensities=(1<<(common.bits_per_pixel - common.pixel_pad_bits));
  }
else {
  common.number_of_intensities=(1<<(common.bits_per_pixel + common.pixel_pad_bits));
  }
if (common.colour_scheme) {
  if (prepare_print(common.colour_scheme)) {
    if (common.number_of_cartridges > 0) {
      common.actual_cartridge=0;
      common.actual_colour=find_next_cartridge_colour(common.actual_cartridge,
                                                     -1);
      common.actual_column=1;
      /* Build calibration file */
      if ((common.actual_colour < common.number_of_basic_colours)  &&
          build_print_colours(FALSE,
                              NULL)) {
        /* Create and show Colour Dialog box */
        if ((error_os=toolbox_create_object(0,
                                            "ColourDbox",
                                            &common.colour_dbox)) != NULL) {
          wimp_report_error(error_os,
                            0,
                            APPLICATION_NAME,
                            0,
                            0,
                            0);
          drop_application();
          exit(EXIT_FAILURE);
          }
        if ((error_os=event_register_toolbox_handler(common.colour_dbox,
                                                     ColourDbox_ColourSelected,
                                                     check_colour,
                                                     NULL)) != NULL) {
          wimp_report_error(error_os,
                            0,
                            APPLICATION_NAME,
                            0,
                            0,
                            0);
          drop_application();
          exit(EXIT_FAILURE);
          }
        if ((error_os=event_register_toolbox_handler(common.colour_dbox,
                                                     ColourDbox_AboutToBeShown,
                                                     set_colour,
                                                     NULL)) != NULL) {
          wimp_report_error(error_os,
                            0,
                            APPLICATION_NAME,
                            0,
                            0,
                            0);
          drop_application();
          exit(EXIT_FAILURE);
          }
        /* Display the generated Draw file */
        system("Filer_Run <Wimp$ScrapDir>.PDPEICal.Pattern");
        }
      }
    else {
      common.calibration_process_flag=FALSE;
      }
    }
  else {
    common.calibration_process_flag=FALSE;
    }
  }
else {
  if (strlen(common.extern_calibration_file_name) > 0) {
    /* Only paper colour in this case */
    if (set_basic_colours(common.colour_scheme)) {
      build_print_colours(TRUE,
                          common.extern_calibration_file_name);
      /* Clean up */
      if (common.basic_colour) {
        free(common.basic_colour);
        common.basic_colour=NULL;
        }
      }
    }
  common.calibration_process_flag=FALSE;
  }
return TRUE;
}

int delete_calibration(int event_code, ToolboxEvent *event, IdBlock *id_block, void *client_handle)
{
char h[20];
int i;
unsigned int button_flags;
_kernel_oserror *error_os;

/* Check whether calibration file has been changed */
if ((error_os=gadget_get_flags(0,
                               id_block->self_id,
                               COMPONENT_START_CALIBRATION_FILE,
                               &button_flags)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
if ((button_flags & Gadget_Faded) == 0) {
  check_and_set_calibration_file(id_block->self_id);
  }
/* Evaluate the dialog settings */
/* Get calibration number */
if ((error_os=stringset_get_selected(0,
                                     id_block->self_id,
                                     COMPONENT_CALIBRATION_NUMBER,
                                     h,
                                     19,
                                     &i)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
h[19]='\0';
common.calibration=atol(h);
modify_calibration_file(FALSE,
                        FALSE,
                        NULL);
update_calibration_list(id_block->self_id);
return TRUE;
}

int change_calibration_file(int event_code, ToolboxEvent *event, IdBlock *id_block, void *client_handle)
{

check_and_set_calibration_file(id_block->self_id);
update_calibration_list(id_block->self_id);
return TRUE;
}

int change_of_calibration_file_name(int event_code, ToolboxEvent *event, IdBlock *id_block, void *client_handle)
{
int size;
char name[500];
unsigned int button_flags;
_kernel_oserror *error_os;

/* Check whether calibration file has been changed */
if (id_block->self_component != COMPONENT_CALIBRATION_FILE) {
  return TRUE;
  }
if ((error_os=gadget_get_flags(0,
                               id_block->self_id,
                               COMPONENT_START_CALIBRATION_FILE,
                               &button_flags)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
size=499;
name[size]='\0';
if ((error_os=writablefield_get_value(0,
                                      id_block->self_id,
                                      COMPONENT_CALIBRATION_FILE,
                                      name,
                                      size,
                                      &size)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
if ((button_flags & Gadget_Faded) != 0) {
  if (strcmp(name, common.calibration_file_name) != 0) {
    if ((error_os=gadget_set_flags(0,
                                   id_block->self_id,
                                   COMPONENT_START_CALIBRATION_FILE,
                                   button_flags & (~Gadget_Faded))) != NULL) {
      wimp_report_error(error_os,
                        0,
                        APPLICATION_NAME,
                        0,
                        0,
                        0);
      drop_application();
      exit(EXIT_FAILURE);
      }
    }
  }
else {
  if (strcmp(name, common.calibration_file_name) == 0) {
    if ((error_os=gadget_set_flags(0,
                                   id_block->self_id,
                                   COMPONENT_START_CALIBRATION_FILE,
                                   button_flags | Gadget_Faded)) != NULL) {
      wimp_report_error(error_os,
                        0,
                        APPLICATION_NAME,
                        0,
                        0,
                        0);
      drop_application();
      exit(EXIT_FAILURE);
      }
    }
  }
return TRUE;
}

int change_of_number_of_bits(int event_code, ToolboxEvent *event, IdBlock *id_block, void *client_handle)
{
char h[20];
int i;
_kernel_oserror *error_os;

/* Check whether number of Bits per pixel has been changed */
if (id_block->self_component != COMPONENT_BITS_PER_PIXEL) {
  return TRUE;
  }
/* Get number of bits per pixel */
if ((error_os=stringset_get_selected(0,
                                     id_block->self_id,
                                     COMPONENT_BITS_PER_PIXEL,
                                     h,
                                     19,
                                     &i)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
h[19]='\0';
/* Set default */
if ((error_os=stringset_set_selected(0,
                                     id_block->self_id,
                                     COMPONENT_PIXEL_PAD_BITS,
                                     "0")) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
/* Set possible values for pad bits accordingly */
if ((error_os=stringset_set_available(0,
                                      id_block->self_id,
                                      COMPONENT_PIXEL_PAD_BITS,
                                      get_pad_bit_values(atoi(h)))) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
return TRUE;
}

int update_cartridge_string_number(int event_code, ToolboxEvent *event, IdBlock *id_block, void *client_handle)
{
int i;
char number_text[10];
int actual_cartridge;
int button_state;
_kernel_oserror *error_os;

actual_cartridge=0;
for (i=0; i < 13; i++) {
  if ((error_os=optionbutton_get_state(0,
                                       id_block->self_id,
                                       i + COMPONENT_COLOR_SELECTION,
                                       &button_state)) != NULL) {
    wimp_report_error(error_os,
                      0,
                      APPLICATION_NAME,
                      0,
                      0,
                      0);
    drop_application();
    exit(EXIT_FAILURE);
    }
  if (button_state == 1) {
    /* Number to Line Pass/Start text */
    switch(actual_cartridge) {
      case 0: {
        strcpy(number_text, "LS1");
        }
      break;
      case 1: {
        strcpy(number_text, "LP1");
        }
      break;
      case 2: {
        strcpy(number_text, "LP2");
        }
      break;
      case 3: {
        strcpy(number_text, "LP3");
        }
      break;
      case 4: {
        strcpy(number_text, "LP4");
        }
      break;
      case 5: {
        strcpy(number_text, "LS2");
        }
      break;
      case 6: {
        strcpy(number_text, "LP1b");
        }
      break;
      case 7: {
        strcpy(number_text, "LP2b");
        }
      break;
      case 8: {
        strcpy(number_text, "LP3b");
        }
      break;
      case 9: {
        strcpy(number_text, "LP4b");
        }
      break;
      default: {
        sprintf(number_text,
                "%d",
                actual_cartridge);
        }
      }
    if ((error_os=displayfield_set_value(0,
                                         id_block->self_id,
                                         i + COMPONENT_COLOR_STRING,
                                         number_text)) != NULL) {
      wimp_report_error(error_os,
                        0,
                        APPLICATION_NAME,
                        0,
                        0,
                        0);
      drop_application();
      exit(EXIT_FAILURE);
      }
    actual_cartridge++;
    }
  else {
    if ((error_os=displayfield_set_value(0,
                                         id_block->self_id,
                                         i + COMPONENT_COLOR_STRING,
                                         "")) != NULL) {
      wimp_report_error(error_os,
                        0,
                        APPLICATION_NAME,
                        0,
                        0,
                        0);
      drop_application();
      exit(EXIT_FAILURE);
      }
    }
  }
return TRUE;
}

int show_calibration_window(int event_code, ToolboxEvent *event, IdBlock *id_block, void *client_handle)
{
char h[20];
int i;
char file_name[300];
char command[300];
FILE *check_file;
_kernel_oserror *error_os;
_kernel_swi_regs regs;
ObjectId window;

/* Block more than one calibration process */
if (common.calibration_process_flag) {
  return TRUE;
  }
common.calibration_process_flag=TRUE;
strcpy(common.calibration_file_name, "");
/* Get actual printer name */
/* Necassary because it is not explicitly set to zero if no printer exists */
regs.r[4]=0;
_kernel_swi(PDriver_Info, &regs, &regs);
if (regs.r[4]) {
  /* Fehlt bei Fehler */
  strcpy(common.printer_name, (char *) regs.r[4]);
  /* Check for local calibration file */
  sprintf(file_name,
          "<PDPEICal$ConfDir>.%s",
          common.printer_name);
  check_file=fopen(file_name, "r");
  if (check_file) {
    fclose(check_file);
    sprintf(common.calibration_file_name,
            "<PDPEICal$ConfDir>.%s",
            common.printer_name);
    }
  else {
    /* Try to generate from existing file */
    sprintf(file_name,
            "<PDPEICal$Dir>.Resources.Calibs.%s",
            common.printer_name);
    check_file=fopen(file_name, "r");
    if (check_file) {
      fclose(check_file);
      sprintf(command,
              "Copy <PDPEICal$Dir>.Resources.Calibs.%s <PDPEICal$ConfDir>.%s ~CFN~V",
              common.printer_name,
              common.printer_name);
      system(command);
      show_message(100, common.printer_name);
      common.calibration_process_flag=FALSE;
      return TRUE;
      }
    }
  }
else {
  show_message(0);
  common.calibration_process_flag=FALSE;
  return TRUE;
  }
/* Generate the calibration window */
if ((error_os=toolbox_create_object(0,
                                    "PrinterConf",
                                    &window)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
common.window=window;
/* Set printer name as title */
if ((error_os=window_set_title(0,
                               window,
                               common.printer_name)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
/* Show supplied PDFs */
#ifndef DEBUG_MODE
system("Filer_OpenDir <PDPEICal$Dir>.Resources.Calibs");
#endif
/* Set own calibration file */
if ((error_os=writablefield_set_value(0,
                                      window,
                                      COMPONENT_CALIBRATION_FILE,
                                      common.calibration_file_name)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
update_calibration_list(window);
/* Set pad Bits range according Bits per pixel */
/* Get number of bits per pixel */
if ((error_os=stringset_get_selected(0,
                                     window,
                                     COMPONENT_BITS_PER_PIXEL,
                                     h,
                                     19,
                                     &i)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
h[19]='\0';
/* Set possible values for pad bits accordingly */
if ((error_os=stringset_set_available(0,
                                      window,
                                      COMPONENT_PIXEL_PAD_BITS,
                                      get_pad_bit_values(atoi(h)))) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
/* Install handlers */
if ((error_os=event_register_toolbox_handler(window,
                                             APP_TBE_START_CALIBRATION,
                                             start_calibration,
                                             NULL)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
if ((error_os=event_register_toolbox_handler(window,
                                             APP_TBE_DELETE_CALIBRATION,
                                             delete_calibration,
                                             NULL)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
if ((error_os=event_register_toolbox_handler(window,
                                             APP_TBE_CATRIDGE_USAGE_CHANGED,
                                             update_cartridge_string_number,
                                             NULL)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
if ((error_os=event_register_toolbox_handler(window,
                                             Window_HasBeenHidden,
                                             stop_calibration,
                                             NULL)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
if ((error_os=event_register_toolbox_handler(window,
                                             APP_TBE_SET_CALIB_FILE,
                                             change_calibration_file,
                                             NULL)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
if ((error_os=event_register_toolbox_handler(window,
                                             WritableField_ValueChanged,
                                             change_of_calibration_file_name,
                                             NULL)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
if ((error_os=event_register_message_handler(Wimp_MDataLoad,
                                             drag_calibration_file_name,
                                             0)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
if ((error_os=event_register_toolbox_handler(window,
                                             StringSet_ValueChanged,
                                             change_of_number_of_bits,
                                             NULL)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
/* Open the calibration window */
if ((error_os=toolbox_show_object(0,
                                  window,
                                  0,
                                  NULL,
                                  0,
                                  0)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
return TRUE;
}

/* ---------- Message Handling --------- */
int program_quitM(WimpMessage *message, void *client_handle)
{

common.shutdown_flag=TRUE;
return TRUE;
}

/* ---------- Menue Handling --------- */
int show_general_help(int event_code, ToolboxEvent *event, IdBlock *id_block, void *client_handle)
{
_kernel_swi_regs regs;

regs.r[0]=(int) "<PDPEICal$Dir>.!Help";
_kernel_swi(Wimp_StartTask, &regs, &regs);
return TRUE;
}

int show_calibration_help(int event_code, ToolboxEvent *event, IdBlock *id_block, void *client_handle)
{

_kernel_swi_regs regs;

regs.r[0]=(int) "<PDPEICal$Dir>.!Help calibration";
_kernel_swi(Wimp_StartTask, &regs, &regs);
return TRUE;
}

/* ---------- Main Loop --------- */
int main(int argc, char *argv[])
{
int event_code,
    toolbox_events=0,
    wimp_messages=0;
int task, wversion;
void *sprite_area;
_kernel_swi_regs regs;
_kernel_oserror *error_os;
/* Evaluation */
unsigned long min_time;

/* General initializations */
if (!initialize_application()) {
  exit(EXIT_FAILURE);
  }
/* Register to Wimp/Toolbox */
if ((error_os=toolbox_initialise(0,
                                 WimpVersion,
                                 &wimp_messages,
                                 &toolbox_events,
                                 "<PDPEICal$Dir>",
                                 &messages,
                                 &id_block,
                                 &wversion,
                                 &task,
                                 &sprite_area)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    0,
                    APPLICATION_NAME,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
if ((error_os=event_initialise(&id_block)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    0,
                    APPLICATION_NAME,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
/* No Null Events */
event_set_mask(1);
/* Installation of procedures to handle certain events */
if ((error_os=event_register_toolbox_handler(-1,
                                             TB_Quit,
                                             program_quitT,
                                             NULL)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
if ((error_os=event_register_toolbox_handler(-1,
                                             Iconbar_Clicked,
                                             show_calibration_window,
                                             NULL)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
if ((error_os=event_register_message_handler(Wimp_MQuit,
                                             program_quitM,
                                             NULL)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
/* Installation of procedures to handle menue events */
if ((error_os=event_register_toolbox_handler(-1,
                                             APP_TBE_SHOW_GENERAL_HELP,
                                             show_general_help,
                                             NULL)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
if ((error_os=event_register_toolbox_handler(-1,
                                             APP_TBE_SHOW_CALIBRATION_HELP,
                                             show_calibration_help,
                                             NULL)) != NULL) {
  wimp_report_error(error_os,
                    0,
                    APPLICATION_NAME,
                    0,
                    0,
                    0);
  drop_application();
  exit(EXIT_FAILURE);
  }
/* central loop */
while(!common.shutdown_flag) {
  _kernel_swi(OS_ReadMonotonicTime, &regs, &regs);
  min_time=regs.r[0]+1000;
  /* Determine polling time */
  if ((error_os=event_poll_idle(&event_code,
                                &poll_block,
                                min_time,
                                NULL)) != NULL) {
    wimp_report_error(error_os,
                      0,
                      APPLICATION_NAME,
                      0,
                      0,
                      0);
    drop_application();
    exit(EXIT_FAILURE);
    }
  }
/* finish program */
drop_application();
exit(EXIT_SUCCESS);
}
