/* DECMONO2.C - MAIN PROGRAM FOR DECODING PICTURES, USING VARIOUS SCHEMES. */

#include <stdio.h>
#include "code.h"


/* CONSTANTS. */

#define Height 700			/* Height of images                 */
#define Width 576                       /* Width of images                  */

#define Margin 3			/* Number of 0s in margins of image */

#define Max_context_pixels 16		/* Max number of pixels in a context*/
#define Max_contexts (1<<Max_context_pixels)  /* Max number of contexts     */
#define Max_used 17			/* Maximum number of context sets   */


/* THE IMAGE.  Holds all the pixels, with borders of size Margin on the
   top, left, and right set to 0.  */

static int image[Height+Margin][Width+2*Margin]; 


/* POSITIONS OF PIXELS MAKING UP A CONTEXT.  Gives the horizontal and vertical
   offsets from the current pixel to the pixel in the context, in order from 
   most to least relevant.  A context of size c is obtained by taking the first
   c of these pixels.   (The numbers below help show different size contexts.)

   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  */

static int ctx_h[Max_context_pixels] = 
{ -1,  0, -1,  1, -2,  0, -1,  1, -2,  2, -2,  2, -3,  0, -1,  1 };

static int ctx_v[Max_context_pixels] =
{  0, -1, -1, -1,  0, -2, -2, -2, -1, -1, -2, -2,  0, -3, -3, -3 };



/* TABLES OF COUNTS OF 0s AND 1s IN EACH CONTEXT.  The freq0 and freq1 
   arrays hold counts of how many 0s and 1s have been seen in different
   contexts, multiplied by 10, with an offset added (eg, 10 for the Laplace
   scheme, representing one).  There are as many such sets of counts as 
   there are sets of contexts being used. */

static int freq0[Max_used][Max_contexts]; /* Frequencies of '0' in contexts */
static int freq1[Max_used][Max_contexts]; /* Frequencies of '1' in contexts */


/* PRINT USAGE MESSAGE AND EXIT. */

static usage(void)
{ fprintf(stderr,
   "Usage: decmono2 [-a] ctx-size init-count { min-occur ctx-size init-count }\n");
  exit(1);
}


/* MAIN PROGRAM. */

main 
( int argc,
  char **argv
)
{   
    int incr_all;			/* Increment counts in all contexts? */
    int n_used;				/* Number of sets of contexts used  */
    int cont_pix[Max_used];		/* Number of pixels in context sets */ 
    int n_contexts[Max_used];		/* Number of contexts (1<<cont_pix) */
    int init_count[Max_used];		/* Initial count for each context   */
    int min_occur[Max_used];		/* Minimum number of occurrances 
					     needed to use this context */
    int h, i, j, k, x, xb;
    char junk;

    /* Look at program arguments. */

    incr_all = 0;
    if (argc>1 && strcmp(argv[1],"-a")==0) {
        incr_all = 1;
        argc -= 1;
        argv += 1;
    }

    if (argc<3 || argc%3!=0)  
        usage();

    n_used = argc/3;
    if (n_used>Max_used) {
        fprintf(stderr, "Too many context sets specified (max %d)\n", Max_used);
        exit(1);
    }
   
    for (h = 0; h<n_used; h++) {
        if (sscanf(argv[1+3*h],"%d%c",&cont_pix[h],&junk)!=1
         || sscanf(argv[2+3*h],"%d%c",&init_count[h],&junk)!=1
         || init_count[h]<1)
            usage();
        if (cont_pix[h]>Max_context_pixels 
         || h>0 && cont_pix[h]>=cont_pix[h-1]) {
            fprintf (stderr, "Illegal number of pixels in context\n");
            exit(1);
        }
        if (h!=n_used-1) {
            if (sscanf(argv[3+3*h],"%d%c",&min_occur[h],&junk)!=1 
             || min_occur[h]<1)
                usage();
        }
        n_contexts[h] = 1<<cont_pix[h];
    }

    min_occur[n_used-1] = 0;  /* Use the last context even if not seen before */

    /* Start IO. */

    start_outputing_bits();
    start_inputing_bits();
    start_decoding();

    /* Initialize the contexts. */

    for (h = 0; h<n_used; h++) {
        for (x = 0; x<n_contexts[h]; x++) {
            freq0[h][x] = init_count[h];
            freq1[h][x] = init_count[h];
        }
    }

    /* Decode image.  Loops through all the pixels in raster scan order. */

    for (i = Margin; i<Height+Margin; i++) {
        for (j = Margin; j<Width+Margin; j++) {

            /* Collect together the pixels in the largest context being used. */

            x = 0;
            for (k = 0; k<cont_pix[0]; k++) {
                x <<= 1;
                x |= image[i+ctx_v[k]][j+ctx_h[k]];
            }

            /* Loop through the context sets, from biggest to smallest, looking
               for one that's been seen often enough.  Sets xb to the context.*/

            for (h = 0; ; h++) {
                xb = x >> (cont_pix[0]-cont_pix[h]);
                if (freq0[h][xb]+freq1[h][xb]-2*init_count[h]>=10*min_occur[h]) 
                    break;
            }

            /* Decode using the context found, and write out pixel. */
    
            image[i][j] = decode_bit (freq0[h][xb], freq1[h][xb]);
            output_bit(image[i][j]);

            /* Increment the counts for this and larger contexts, or for
               all contexts if the -a argument was given. */

            for (h = incr_all? n_used-1 : h; h>=0; h--) {
                xb = x >> (cont_pix[0]-cont_pix[h]);
                if (image[i][j]) 
                    freq1[h][xb] += 10;
                else 
                    freq0[h][xb] += 10;
                if (freq0[h][xb]+freq1[h][xb]>Freq_full) { 
                    freq0[h][xb] = (freq0[h][xb]+1) >> 1; 
                    freq1[h][xb] = (freq1[h][xb]+1) >> 1;
                }
            }
        }
    }

    /* Send the last few bits.  */

    done_outputing_bits();

    exit(0);
}

