/*-----------------------------------------*/
/* File : utils.c, utilities for jfif view */
/* Author : Pierre Guerrier, march 1998	   */
/*-----------------------------------------*/



#include <io.h>
#include <system.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>

#include "jpeg.h"
#define RAM_SIZE (2<<16) // in number of words

#define IOWR_RECT_DATA(base, offset, data) \
  IOWR_16DIRECT(base, (offset)*2, data) 

/* Prints a data block in frequency space. */
void
show_FBlock(FBlock *S)
{
  int i,j;

  for (i=0; i<8; i++) {
    for (j=0; j<8; j++)
      fprintf(stderr, "\t%d", S->block[i][j]);
    fprintf(stderr, "\n");
  }
}

/* Prints a data block in pixel space. */
void
show_PBlock(PBlock *S)
{
  int i,j;

  for (i=0; i<8; i++) {
    for (j=0; j<8; j++)
      fprintf(stderr, "\t%d", S->block[i][j]);
    fprintf(stderr, "\n");
  }
}

/* Prints the next 800 bits read from file `fi'. */
void
bin_dump(FILE *fi)
{
  int i;

  for (i=0; i<100; i++) {
    unsigned int bitmask;
    int c = fgetc(fi);

    for (bitmask = 0x80; bitmask; bitmask >>= 1)
      fprintf(stderr, "\t%1d", !!(c & bitmask));
    fprintf(stderr, "\n");
  }
}


/*-------------------------------------------*/
/* core dump generator for forensic analysis */
/*-------------------------------------------*/

void
suicide(void)
{
  int *P;

  fflush(stdout);
  fflush(stderr);
  P = NULL;
  *P = 1;
}


/*-------------------------------------------*/


void
aborted_stream(FILE *fi, FILE *fo)
{
    
  printf("\tOops! Aborted Stream\n");

  fprintf(stderr, "\tINFO:\tTotal skipped bytes %d, total stuffers %d\n",
	  passed, stuffers);



  if (DEBUG) RGB_save(fo); else free_structures();


  if (DEBUG) suicide(); else return;
}


/*----------------------------------------------------------*/

/* Returns ceil(N/D). */
int
ceil_div(int N, int D)
{
  int i = N/D;

  if (N > D*i) i++;
  return i;
}


/* Returns floor(N/D). */
int
floor_div(int N, int D)
{
  int i = N/D;

  if (N < D*i) i--;
  return i;
}


/*----------------------------------------------------------*/

/* For all components reset DC prediction value to 0. */
void
reset_prediction(void)
{
  int i;

  for (i=0; i<3; i++) comp[i].PRED = 0;
}


/*---------------------------------------------------------*/


/* Transform JPEG number format into usual 2's-complement format. */
int
reformat(unsigned long S, int good)
{
  int St;
 
  if (!good)
    return 0;
  St = 1 << (good-1);	/* 2^(good-1) */
  if (S < (unsigned long) St)
    return (S+1+((-1) << good));
  else
    return S;
}


/*----------------------------------------------------------*/

void
free_structures(void)
{
  int i;

  for (i=0; i<4; i++) if (QTvalid[i]) free(QTable[i]);

  free(ColorBuffer);
  free(FrameBuffer);

  for (i=0; MCU_valid[i] != -1; i++) free(MCU_buff[i]);
   free(input_buffer);
}


/*-------------------------------------------*/
/* this is to save final RGB image to disk   */
/* using the sunraster uncompressed format   */
/*-------------------------------------------*/

/* Sun raster header */

typedef struct {
  unsigned long	MAGIC;
  unsigned long	Width;
  unsigned long	Heigth;
  unsigned long	Depth;
  unsigned long	Length;
  unsigned long	Type;
  unsigned long	CMapType;
  unsigned long	CMapLength;
} sunraster;




    


void
RGB_save(FILE *fo)
{
   /*fo = stdout;*/
   
   
//     printf ("in RGB save\n");
  sunraster *FrameHeader;
  int i, j, k;
  unsigned long bigendian_value;
  
  FrameHeader = (sunraster *) malloc(sizeof(sunraster));
  FrameHeader->MAGIC      = 0x59a66a95L;
  FrameHeader->Width      = x_size; //2 * ceil_div(x_size, 2); /* round to 2 more */
  FrameHeader->Heigth     = y_size;
  FrameHeader->Depth      = (n_comp>1) ? 24 : 8;
  FrameHeader->Length     = 0;	/* not required in v1.0 */
  FrameHeader->Type       = 0;	/* old one */
  FrameHeader->CMapType   = 0;	/* truecolor */
  FrameHeader->CMapLength = 0;	/* none */

  /* Frameheader must be in Big-Endian format */
  int sample_rate = 1;
  unsigned int new_width = FrameHeader->Width ;
  unsigned int new_height = FrameHeader->Heigth;
  
  while ((new_width * new_height)> (RAM_SIZE))
  {
    
        sample_rate++;
        new_width = FrameHeader->Width /sample_rate;
        new_height = FrameHeader->Heigth/sample_rate;
        
        
    }
  
  
  
  
unsigned int count =0;
unsigned int addr =0;
  for (i=0; i<480; i++)
    for (j=0; j<640; j++)
        {
         unsigned int to_out=0;
            for (k =0; k<n_comp;k++)
                {
                       unsigned char temp = FrameBuffer[i*x_size*n_comp+j*n_comp+k];// temp is 8 bits
                       to_out = (temp>> 3)<< (k*5) | to_out; 
                       
                }
                
                //Address 1 & 2
            if(i%sample_rate== (sample_rate -1 ) && j%sample_rate==(sample_rate -1))
            {
            addr++;
            IOWR_RECT_DATA(VGA_RASTER_0_BASE, 0x0001,((2*addr)& 0xFFFF));
            IOWR_RECT_DATA(VGA_RASTER_0_BASE, 0x0002,((2*addr)>>16));
            IOWR_RECT_DATA(VGA_RASTER_0_BASE, 0x0000, 0x0000);     
            }
            count++;
           // printf("%d ", count);
            //(FrameBuffer+n_comp*i*x_size, n_comp, FrameHeader->Width, fo);
        }
  
  
 //  printf("%d ", x_size* n_comp);
 //  printf("%d", y_size);
 
/*#if 1
  
#define MACHINE_2_BIGENDIAN(value)\
 ((( (value) & (unsigned long)(0x000000FF)) << 24) | \
  (( (value) & (unsigned long)(0x0000FF00)) << 8) | \
  (( (value) & (unsigned long)(0x00FF0000)) >> 8) | \
  (( (value) & (unsigned long)(0xFF000000)) >> 24))
  
  bigendian_value = MACHINE_2_BIGENDIAN(FrameHeader->MAGIC);
  fwrite(&bigendian_value, 4, 1, fo);
  
  bigendian_value = MACHINE_2_BIGENDIAN(FrameHeader->Width);
  fwrite(&bigendian_value, 4, 1, fo);
  
  bigendian_value = MACHINE_2_BIGENDIAN(FrameHeader->Heigth);
  fwrite(&bigendian_value, 4, 1, fo);
  
  bigendian_value = MACHINE_2_BIGENDIAN(FrameHeader->Depth);
  fwrite(&bigendian_value, 4, 1, fo);
  
  bigendian_value = MACHINE_2_BIGENDIAN(FrameHeader->Length);
  fwrite(&bigendian_value, 4, 1, fo);
  
  bigendian_value = MACHINE_2_BIGENDIAN(FrameHeader->Type);
  fwrite(&bigendian_value, 4, 1, fo);
  
  bigendian_value = MACHINE_2_BIGENDIAN(FrameHeader->CMapType);
  fwrite(&bigendian_value, 4, 1, fo);
  
  bigendian_value = MACHINE_2_BIGENDIAN(FrameHeader->CMapLength);
  fwrite(&bigendian_value, 4, 1, fo);
  
#else
  fwrite(FrameHeader, sizeof(sunraster), 1, fo);
#endif*/
  IOWR_RECT_DATA(VGA_RASTER_0_BASE, 0x0003, (new_width ));
  IOWR_RECT_DATA(VGA_RASTER_0_BASE, 0x0004, (new_height));   
count =0;
addr =0;
  for (i=0; i<FrameHeader->Heigth; i++)
    for (j=0; j<FrameHeader-> Width; j++)
        {
         unsigned int to_out=0;
            for (k =0; k<n_comp;k++)
                {
                       unsigned char temp = FrameBuffer[i*x_size*n_comp+j*n_comp+k];// temp is 8 bits
                       to_out = (temp>> 3)<< (k*5) | to_out; 
                       
                }
                
                //Address 1 & 2
            if(i%sample_rate== (sample_rate -1 ) && j%sample_rate==(sample_rate -1))
            {
            addr++;
            IOWR_RECT_DATA(VGA_RASTER_0_BASE, 0x0001,((2*addr)& 0xFFFF));
            IOWR_RECT_DATA(VGA_RASTER_0_BASE, 0x0002,((2*addr)>>16));
            IOWR_RECT_DATA(VGA_RASTER_0_BASE, 0x0000, to_out);     
            }
            count++;
           // printf("%d ", count);
            //(FrameBuffer+n_comp*i*x_size, n_comp, FrameHeader->Width, fo);
        }

        
      // clean_up(); 
}
