/* image.c - Calibration and image handling functions
 * 
 * Copyright (C) 2004, 2005 Anderson Lizardo
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc., 59
 * Temple Place, Suite 330, Boston, MA  02111-1307 USA
*/

/* Disabled by now, until code gets fixed */
#if 0
#include <stdlib.h>
#include <math.h>

#include "geniusvp2-adc.h"
#include "geniusvp2-asic.h"
#include "geniusvp2-image.h"
#include "geniusvp2-misc.h"

const int color_table_size = 4096;

int redmax, greenmax, bluemax, redmin, greenmin, bluemin;

/* 
 * Calculate the color matrix
 */
void
calc_color_table (scan_image * image)
{
    int i;
    double midin, val, m, b;
    int maxin = color_table_size - 1;
    int maxout = 255;

    /* do the gamma correction observing the actual range of input data */

    midin = (double) (redmin + redmax) / 2.0;
    b = (1.0 + image->color[0].brightness / 100.0) * midin;
    m = 1.0 + image->color[0].contrast / 100.0;
    for (i = 0; i <= maxin; i++)
    {
        val = ((double) i - midin) * m + b;
        if ((int) val < redmin)
            image->color_table[0][i] = 0;
        else
        {
            if ((int) val > redmax)
                image->color_table[0][i] = 255;
            else
            {
                image->color_table[0][i] =
                    maxout * pow ((val - (double) redmin) /
                                  (double) (redmax - redmin),
                                  (1.0 / image->color[0].gamma));
            }
        }
    }

    midin = (double) (greenmin + greenmax) / 2.0;
    b = (1.0 + image->color[1].brightness / 100.0) * midin;
    m = 1.0 + image->color[1].contrast / 100.0;
    for (i = 0; i <= maxin; i++)
    {
        val = ((double) i - midin) * m + b;
        if ((int) val < greenmin)
            image->color_table[1][i] = 0;
        else
        {
            if ((int) val > greenmax)
                image->color_table[1][i] = 255;
            else
            {
                image->color_table[1][i] =
                    maxout * pow ((val - (double) greenmin) /
                                  (double) (greenmax - greenmin),
                                  (1.0 / image->color[1].gamma));
            }
        }
    }

    midin = (double) (bluemin + bluemax) / 2.0;
    b = (1.0 + image->color[2].brightness / 100.0) * midin;
    m = 1.0 + image->color[2].contrast / 100.0;
    for (i = 0; i <= maxin; i++)
    {
        val = ((double) i - midin) * m + b;
        if ((int) val < bluemin)
            image->color_table[2][i] = 0;
        else
        {
            if ((int) val > bluemax)
                image->color_table[2][i] = 255;
            else
            {
                image->color_table[2][i] =
                    maxout * pow ((val - (double) bluemin) /
                                  (double) (bluemax - bluemin),
                                  (1.0 / image->color[2].gamma));
            }
        }
    }

    DBG (2, "min = %i %i %i  max = %i %i %i \n", redmin, greenmin,
         bluemin, redmax, greenmax, bluemax);
}

void
init_image (scan_image ** image)
{
    int i;

    *image = malloc (sizeof (scan_image));

    (*image)->width = 100;
    (*image)->height = 100;
    (*image)->resolution = 100;
    (*image)->from_top = 0;
    (*image)->from_left = 0;
    (*image)->num_colors = 3;

    for (i = 0; i < 3; i++)
    {
        ((*image)->color)[i].gamma = 1.0;
        ((*image)->color)[i].contrast = 0;
        ((*image)->color)[i].brightness = 0;
        (*image)->color_table[i] = malloc (color_table_size);
    }

    (*image)->filename = malloc (100);
    (*image)->filename = "test.tiff";
}

/* FIXME: Calibration code is broken */
void
calibrate (scan_image * image)
{
    int i, j;
    int *whiteline, redlow, greenlow, bluelow;
    ScanArea area;

    /* Adjust offsets */
    sane_geniusvp2_adjust_offset ();

    area.top = 0;
    area.left = 0;
    area.height = 200;
    area.width = 800;

    sane_geniusvp2_set_scan_area (area);
    sane_geniusvp2_set_scan_params (200);
    sane_geniusvp2_reset_fifo ();
    sane_geniusvp2_set_operation_mode (mStop);
    sane_geniusvp2_set_operation_mode (mScan);

    /*
     * here we are to find out the location of the calibration area and hence the window
     */
    {
        int k, w, ystart;

        ystart = 0;
        for (j = 0; j < 50; j++)
        {
            sane_geniusvp2_wait_fifo (200);
            for (k = 0; k < 200; k++)
                sane_geniusvp2_reg_read (17, &reg17.w);        /* skip over the x-calibration strip */

            w = 0;
            for (i = 0; i < 3; i++)
            {
                sane_geniusvp2_wait_fifo (200);
                for (k = 0; k < 200; k++)
                {
                    sane_geniusvp2_reg_read (17, &reg17.w);
                    w = w + reg17.w;
                }
            }
            if (ystart == 0 && w > 0x78 * 600)
                ystart = j;
        }
    }

    /*sane_geniusvp2_set_operation_mode (mStop);
       ScanSpeed = 7;
       sane_geniusvp2_set_scan_speed (ScanSpeed);

       StepTime = max_exposure_time / (ScanSpeed + 1);
       if (StepTime < min_exposure_time)
       StepTime = min_exposure_time;
       sane_geniusvp2_set_step_time (StepTime);

       sane_geniusvp2_set_distance (0x0006);

       sane_geniusvp2_reg_read (6, &reg6.w);
       reg6.r.MotorPower = 1;
       reg6.r.HalfFull = 1;
       sane_geniusvp2_reg_write (6, reg6.w);
       sane_geniusvp2_set_operation_mode (mBackward);

       sane_geniusvp2_poll_12 (0x08, 0x08);

       if (StepTime >= motor_change)
       sane_geniusvp2_reg_write (25, 0x00);
       else
       sane_geniusvp2_reg_write (25, 0x0f); */

    sane_geniusvp2_go_home ();
    sane_geniusvp2_poll_12 (0x04, 0x04);

    /* Set location of the white area */
    area.top = 236;
    sane_geniusvp2_move_carriage_forward (area.top);
    area.left = 131;
    area.height = 10;
    area.width = 8.5 * 600;

    sane_geniusvp2_set_scan_area (area);
    sane_geniusvp2_set_scan_params (600);
    sane_geniusvp2_reset_fifo ();
    sane_geniusvp2_set_operation_mode (mStop);
    sane_geniusvp2_set_operation_mode (mScan);

    /* Find max reading for each color */
    {
        float redgain, greengain, bluegain;

        redgain = greengain = bluegain = 0.0;
        for (j = 0; j < area.height; j++)
        {
            sane_geniusvp2_wait_fifo (area.width);
            for (i = 0; i < area.width; i++)
            {
                sane_geniusvp2_reg_read (17, &reg17.w);
                if (reg17.w > redgain)
                    redgain = reg17.w;
                sane_geniusvp2_reg_read (17, &reg17.w);
                if (reg17.w > greengain)
                    greengain = reg17.w;
                sane_geniusvp2_reg_read (17, &reg17.w);
                if (reg17.w > bluegain)
                    bluegain = reg17.w;
            }
        }
        /* Convert color gains to ADC register codes */
        redgain = ((210 / redgain) - 0.5) / 0.25;
        greengain = ((225 / greengain) - 0.5) / 0.25;
        bluegain = ((225 / bluegain) - 0.5) / 0.25;

        /* From the read above we can set max gain for each color */
        sane_geniusvp2_set_adc_gain (redgain, greengain, bluegain);
    }
    /* Try out a new set of offsets for the current gain settings */
    sane_geniusvp2_adjust_offset ();

    /* Do an extra read to see the final result */
    sane_geniusvp2_get_avg_reading (&redmin, &greenmin, &bluemin);

    area.top = 0;
    area.left = 131;
    area.height = 40;
    area.width = 8.5 * 600;
    sane_geniusvp2_set_scan_area (area);
    sane_geniusvp2_set_scan_params (600);
    sane_geniusvp2_reset_fifo ();
    sane_geniusvp2_set_operation_mode (mStop);
    sane_geniusvp2_set_operation_mode (mScan);

    /* Test of calibration */
    whiteline = calloc (5100 * 3, sizeof (int));

    for (j = 0; j < 10; j++)
    {
        sane_geniusvp2_wait_fifo (5100);
        for (i = 0; i < 5100 * 3; i += 3)
        {
            sane_geniusvp2_reg_read (17, &reg17.w);
            whiteline[i] = whiteline[i] + reg17.w;
            sane_geniusvp2_reg_read (17, &reg17.w);
            whiteline[i + 1] = whiteline[i + 1] + reg17.w;
            sane_geniusvp2_reg_read (17, &reg17.w);
            whiteline[i + 2] = whiteline[i + 2] + reg17.w;
        }

    }

    for (i = 0; i < 5100 * 3; i++)
        whiteline[i] = whiteline[i] / 10;

    /* Find the highest reading for each color */
    redlow = greenlow = bluelow = 0;
    for (i = 0; i < 5100 * 3; i += 3)
    {
        if (whiteline[i] > redlow)
            redlow = whiteline[i];
        if (whiteline[i + 1] > greenlow)
            greenlow = whiteline[i + 1];
        if (whiteline[i + 2] > bluelow)
            bluelow = whiteline[i + 2];
    }

    /* Load the x-direction map */
    sane_geniusvp2_set_memory_addr (0x006000);

    redmax = 32 * (redlow - 124);
    greenmax = 32 * (greenlow - 124);
    bluemax = 32 * (bluelow - 124);

    for (i = 0; i < 132; i++)
        sane_geniusvp2_reg_write (17, 0);
    for (i = 0; i < 5100; i++)
        sane_geniusvp2_reg_write (17, (redlow - whiteline[i * 3]) * 3);
    for (i = 0; i < 912; i++)
        sane_geniusvp2_reg_write (17, 0);

    for (i = 0; i < 132; i++)
        sane_geniusvp2_reg_write (17, 0);
    for (i = 0; i < 1916; i++)
        sane_geniusvp2_reg_write (17, (redlow - whiteline[i * 3]) * 3);

    for (i = 0; i < 132; i++)
        sane_geniusvp2_reg_write (17, 0);
    for (i = 0; i < 5100; i++)
        sane_geniusvp2_reg_write (17, (greenlow - whiteline[i * 3 + 1]) * 3);
    for (i = 0; i < 912; i++)
        sane_geniusvp2_reg_write (17, 0);

    for (i = 0; i < 132; i++)
        sane_geniusvp2_reg_write (17, 0);
    for (i = 0; i < 5100; i++)
        sane_geniusvp2_reg_write (17, (bluelow - whiteline[i * 3 + 2]) * 3);
    for (i = 0; i < 912; i++)
        sane_geniusvp2_reg_write (17, 0);

    free (whiteline);

    sane_geniusvp2_set_memory_addr (0x003000);
    for (i = 0; i < 12 * 1024; i += 2)
    {
        sane_geniusvp2_reg_write (17, 0x80);
        sane_geniusvp2_reg_write (17, 0x00);
    }

    calc_color_table (image);   /* Set up the final color-matrix */

    /* Send colormap */
    sane_geniusvp2_set_memory_addr (0x000000);
    for (i = 0; i < 3; i++)
        for (j = 0; j < color_table_size; j++)
            sane_geniusvp2_reg_write (17, (char) (image->color_table[i][j]));
}
#endif
