/**********************************************************************
This file is part of Crack dot Com's free source code release of Golgotha.
for information about compiling & licensing issues visit this URL
 If that doesn't help, contact Jonathan Clark at 
  golgotha_source@usa.net (Subject should have "GOLG" in it) 
***********************************************************************/

#error this file is not USED
#include "tconvert.hh"
#include "error/alert.hh"
#include "loaders/load.hh"
#include "math/point.hh"
#include "image/depth.hh"
#include "image/image8.hh"
#include "image/image32.hh"
#include "string/string.hh"
#include "error/alert.hh"
#include "g1_limits.hh"

#ifndef G1_RETAIL
#include "memory/growarry.hh"
#include "quantize/histogram.hh"
#include "quantize/median.hh"
#include "loaders/fli_load.hh"
#include "loaders/bmp_write.hh"
#include "image/image2.hh"
#include "image/color.hh"
#endif

enum { MAX_MIPS=8 } ;


#ifndef G1_RETAIL
static i4_bool target_needs_update(const i4_const_str &source, const i4_const_str &target)
{
  i4_file_status_struct stat_source, stat_target;
  if (!i4_file_man.get_status(source,stat_source))
    return i4_T;

  if (!i4_file_man.get_status(target,stat_target))  
    return i4_T;

  return (i4_bool) (stat_source.last_modified>stat_target.last_modified);
}
#endif


w32 g1_convert_pal_filename_to_id(const i4_const_str &name)
{
  i4_const_str::iterator pal_end=name.begin();  
  w32 pal_file_id;

  pal_file_id=                    pal_end.get().value();  ++pal_end; 
  pal_file_id= (pal_file_id<<8) | pal_end.get().value();  ++pal_end; 
  pal_file_id= (pal_file_id<<8) | pal_end.get().value();  ++pal_end;
  pal_file_id= (pal_file_id<<8) | pal_end.get().value();  ++pal_end;
  ++pal_end;

  return pal_file_id;
}

#ifndef G1_RETAIL

static i4_image_class *load_if_valid(i4_const_str &fname, 
                                     i4_grow_array &used,
                                     i4_bool new_only,
                                     w32 &match_id)
{
  i4_str *path, *filename, *extension;
  i4_image_class *ret=0;

  i4_file_man.split_path(fname, path, filename, extension);
  if (path) delete path;

  if (extension && *extension==i4gets("tga_ext"))
  {
    w32 id=g1_convert_pal_filename_to_id(*filename);
    i4_bool ok=i4_T;

    if (new_only)
    {
      for (w32 j=0; jbegin();  
  for (w32 j=0; j<5; j++)
    ++pal_end;
  i4_str *pal_name=new i4_str(filename->begin(),pal_end,5);

  if (path) delete path;
  delete filename;
  if (ext) delete ext;

  i4_str *source=i4gets("pal_source_name").sprintf(100,pal_name);
  return source;
}

void g1_create_best_palettes()
{
  i4_str **files, **dirs;
  w32 tfiles, tdirs, i,j;
  i4_image_class *im;

  i4_grow_array calced(128,"calced pals",64);

  if (i4_file_man.get_directory(i4gets("default_tga_dir"), files, tfiles, dirs, tdirs))
  {
    for (i=0; icreate_iterator(0,0);
        for (w32 x=0; x<256; x++) 
        {
          i8->iterator_store(it, x);
          ++it;
        }
        
        i4_file_man.mkdir(i4gets("texture_dir"));
        i4_file_man.mkdir(i4gets("pal_dir"));

        i4_str *target=get_bmp_name(*files[i]);
        i4_file_class *out=i4_file_man.open(*target,i4_file_manager_class::WRITE);
        delete target;

        if (out)
        {
          i4_write_bmp(i8, out);
          delete out;
        }

        delete i8;

      }

    }

    for (i=0; iadd_image_colors(im, 1);
    pal=i4_median_cut(hist, 1);

    i4_unmatched_image8 *i8=new i4_unmatched_image8(256,1,pal);
    i4_unmatched_image8::iterator i=i8->create_iterator(0,0);
    for (w32 x=0; x<256; x++) 
    {
      i8->iterator_store(i, x);
      ++i;
    }

    i4_file_man.mkdir(i4gets("texture_dir"));
    i4_file_man.mkdir(i4gets("pal_dir"));

    i4_file_class *out=i4_file_man.open(target,i4_file_manager_class::WRITE);
    if (!out)
    {
      delete hist;
      delete im;
      delete fp; 
      null_pal_handle(pal);
      return;
    }

    i4_write_bmp(i8, out);
    delete out;
    delete fp;
    delete i8;

    delete hist;
    delete im;
  }

}

#else

void g1_create_best_palettes() { ; }

#endif


static void load_palette(const i4_const_str &name, 
                         const i4_const_str &original_name,
                         w32 *buffer)
{  



  w32 pal_file_id=g1_convert_pal_filename_to_id(name);

  i4_str *target=i4gets("pal_target_name").sprintf(100,
                                                   (pal_file_id>>24)&0xff,
                                                   (pal_file_id>>16)&0xff,
                                                   (pal_file_id>>8)&0xff,
                                                   (pal_file_id)&0xff
                                                   );

#ifndef G1_RETAIL
  i4_str *source=get_bmp_name(name);
  if (target_needs_update(*source,*target))
  {
    i4_image_class *im=i4_load_image(*source);
    i4_pal_handle_class pal;

    if (!im)
    {
      i4_alert(i4gets("pal_file_missing"),120,source,&name);
      save_pal(original_name, *source, pal);
    }
    else
    {
      pal=im->get_pal();
      delete im;
    }

    
    if (pal.source_type()!=I4_8BIT)
      i4_error("palette file is not 8 bit");


    i4_file_class *fp=i4_file_man.open(*target,i4_file_manager_class::WRITE);
    if (!fp)
      i4_error("unable to open palette output file");
    
    w32 *pdata=pal.pal->source.lookup;
    for (w32 i=0; i<256; i++)
      fp->write_32(pdata[i]);
    delete fp;
  }

  delete source;
#endif
  
  i4_file_class *fp=i4_open(*target);
  if (!fp)
  {
    i4_alert(i4gets("file_missing"),100,target);
    i4_error("bye");
  }

  for (w32  i=0; i<256; i++)
    buffer[i]=fp->read_32();
  
  delete fp;
}


#ifndef G1_RETAIL

// this function will average 4 rgb packed colors and return the new rgb color
static inline i4_color average_4_32s(i4_color c1,
                                     i4_color c2,
                                     i4_color c3,
                                     i4_color c4)
{
  enum { r_mask=0xff0000,
         g_mask=0xff00,
         b_mask=0xff,
         r_shift=16,
         g_shift=8,
         b_shift=0 };


  w32 red=(((c1&r_mask)+
            (c2&r_mask)+
            (c3&r_mask)+
            (c4&r_mask))>>r_shift)/4;

  w32 green=(((c1&g_mask)+
              (c2&g_mask)+
              (c3&g_mask)+
              (c4&g_mask))>>g_shift)/4;

  w32 blue=(((c1&b_mask)+
             (c2&b_mask)+
             (c3&b_mask)+
             (c4&b_mask))>>b_shift)/4;

  return (red<width()/2,
                                   im->height()/2,
                                   im->get_pal());
  i4_image2 *small_holy=0;
  i4_image2::iterator hsource1, hsource2, hdest;
  i4_image32::iterator source1, source2, dest;
  
  if (holy)
    small_holy = new i4_image2(holy->width()/2,
                               holy->height()/2,
                               holy->get_pal());
  

  w32 xcounter,ycounter,
    end_skip=(im->width()&1); // in case the image width is odd we need to skip a byte
  
  source1=im->create_iterator(0,0);
  source2=im->create_iterator(0,1);
  dest=small->create_iterator(0,0);

  if (holy)
  {
    hsource1=holy->create_iterator(0,0);
    hsource2=holy->create_iterator(0,1);
    hdest=small_holy->create_iterator(0,0);
  }


  i4_color c1,c2,c3,c4, r,g,b;
  sw32 total_pixels;

  for (ycounter=small->height(); ycounter; ycounter--)
  {
    for (xcounter=small->width(); xcounter; xcounter--)
    {
      c1=im->iterator_get(source1);
      ++source1;
      c2=im->iterator_get(source1);
      ++source1;

      c3=im->iterator_get(source2);
      ++source2;
      c4=im->iterator_get(source2);
      ++source2;


      if (holy)
      {
        total_pixels=0;
        r=g=b=0;

        if (holy->iterator_get(hsource1)) 
        { total_pixels++; r+=(c1&0xff0000)>>16; g+=(c1&0xff00)>>8; b+=(c1&0xff)>>0; }
        ++hsource1;

        if (holy->iterator_get(hsource1))
        { total_pixels++; r+=(c2&0xff0000)>>16; g+=(c2&0xff00)>>8; b+=(c2&0xff)>>0; }
        ++hsource1;

        if (holy->iterator_get(hsource2))
        { total_pixels++; r+=(c3&0xff0000)>>16; g+=(c3&0xff00)>>8; b+=(c3&0xff)>>0; }
        ++hsource2;

        if (holy->iterator_get(hsource2))  
        { total_pixels++; r+=(c4&0xff0000)>>16; g+=(c4&0xff00)>>8; b+=(c4&0xff)>>0; }
        ++hsource2;

        if (total_pixels > (rand()%4))
        {
          small->iterator_store(dest, i4_rgb_to_32bit(r/total_pixels, 
                                                      g/total_pixels,
                                                      b/total_pixels));

          small_holy->iterator_store(hdest, 1);                   
        }
        else
        {
          small->iterator_store(dest, 0);
          small_holy->iterator_store(hdest, 0);
        }

        ++hdest;
        ++dest;
      }
      else
      {
        small->iterator_store(dest,average_4_32s(c1,c2,c3,c4));
        ++dest;
      }    
    }
    if (holy)
    {
      hsource1+=end_skip+im->width();
      hsource2+=end_skip+im->width();
    }

    source1+=end_skip+im->width();
    source2+=end_skip+im->width();
    
  }

  ret_32=small;
  ret_2=small_holy;

}


static i4_image32 *convert_8_to_32(i4_image_class *image8)
{
  i4_pal_handle_class pal;
  i4_unmatched_image8 *im8=(i4_unmatched_image8 *)image8;

  i4_image32 *new32=new i4_image32(im8->width(),
                                   im8->height(),
                                   pal);
  i4_image32::iterator i32=new32->create_iterator(0,0);
  i4_unmatched_image8::iterator i8=im8->create_iterator(0,0);

  w32 *pal_data=image8->get_pal().pal->source.lookup;

  w32 i,t=im8->width()*im8->height();
  for (i=0; iiterator_store(i32, pal_data[ im8->iterator_get(i8) ]);
    ++i32;
    ++i8;
  }
  
  return new32;
}


void clear_holes(i4_unmatched_image8 *im8,
                 i4_image2 *im2)
{  
  i4_unmatched_image8::iterator i8=im8->create_iterator(0,0);
  i4_image2::iterator i2=im2->create_iterator(0,0);

  w32 t=im8->width() * im8->height(), i;

  for (i=0; iiterator_get(i2))
      im8->iterator_store(i8, 0);
    ++i8;
    ++i2;
  }
}

i4_image2 *get_holes(i4_unmatched_image8 *im8)
{  
  w32 pal_d[2]= {0, 0xffffffff};
  i4_pixel_format fmt;
  fmt.pixel_depth=I4_2BIT;
  fmt.lookup=pal_d;

  i4_pal_handle_class pal=i4_pal_man.register_pal(&fmt);

  w32 t=im8->width() * im8->height(), i;

  i4_image2 *im2=new i4_image2(im8->width(), im8->height(), pal);

  i4_unmatched_image8::iterator i8=im8->create_iterator(0,0);
  i4_image2::iterator i2=im2->create_iterator(0,0);

  w32 *pal_data=im8->get_pal().pal->source.lookup;

  w32 index,red,green,blue,rgbcolor;
  i4_bool transparent;
  
  w32 r_mask  = 0x00ff0000;
  w32 g_mask  = 0x0000ff00;
  w32 b_mask  = 0x000000ff;
  w32 r_shift = 16;
  w32 g_shift = 8;
  w32 b_shift = 0;         

  for (i=0; iiterator_get(i8);
    
    rgbcolor = pal_data[index];

    red   = (rgbcolor & r_mask) >> r_shift;
    green = (rgbcolor & g_mask) >> g_shift;
    blue  = (rgbcolor & b_mask) >> b_shift;
    
    transparent = (red==254 && green==2 && blue==166);

    if (!transparent)
      im2->iterator_store(i2, 1);
    else
      im2->iterator_store(i2, 0);
    ++i8;
    ++i2;
  }
  return im2;
}

static i4_bool save_texture(i4_image32 *im, 
                            i4_image2  *holy_patern,
                            const i4_pal_handle_class &pal,
                            w32 pal_id,
                            const i4_const_str &filename)
{
  i4_image32 *mip_levels[MAX_MIPS];
  i4_image2  *holy_levels[MAX_MIPS];

  sw32 i,t_mips=0,w,h;

  i4_file_class *fp=i4_file_man.open(filename, i4_file_manager_class::WRITE);
  if (!fp) return i4_F;
  w=im->width();
  h=im->height();

  mip_levels[0]=im;
  holy_levels[0]=holy_patern;

  for (i=1; iwidth()<4 ||
        mip_levels[i-1]->height()<2)
      break;

    mip_scale(mip_levels[i-1],
              holy_levels[i-1],
              mip_levels[i],
              holy_levels[i]);
    t_mips++;
  }


  fp->write_8(G1_TEXTURE_FILE);
  fp->write_32(pal_id);
  fp->write_16(mip_levels[t_mips-1]->width());
  fp->write_16(mip_levels[t_mips-1]->height());


  for (i=t_mips-1; i>=0; i--)
  {   
    i4_unmatched_image8 *i8=mip_levels[i]->quantize(pal,1,
                                                    0,0,
                                                    mip_levels[i]->width(),
                                                    mip_levels[i]->height());
    if (holy_patern)
      clear_holes(i8, holy_levels[i]);
      

    if (i==0)
    {
      fp->write_16(0);
      fp->write_16(0);
    }
    else
    {
      fp->write_16(mip_levels[i-1]->width());
      fp->write_16(mip_levels[i-1]->height());
    }

    fp->write(i8->local_sub_data(0,0),
              i8->width() * i8->height());
             
    delete i8;
    delete mip_levels[i];
    if (holy_patern)
      delete holy_levels[i];
  } 

  delete fp;

  return i4_T;
}
#endif

g1_texture_handle convert_tga(const i4_const_str &original_name,
                              const i4_const_str &basename,
                              g1_texture_mapper_class &tmapper)
{
  i4_str *target=i4gets("text_name").sprintf(100, &basename);

#ifndef G1_RETAIL
  // see if we need to update the texture
  if (target_needs_update(original_name, *target))  
  {
    i4_alert(i4gets("updating_texture"),100,&original_name);
    i4_image_class *im=i4_load_image(original_name);
    if (!im)
    {
      i4_alert(i4gets("file_missing"), 100, &original_name);
      delete target;
      return 0;
    }
    else if (im->get_pal().source_type()!=I4_32BIT)    
    {
      i4_alert(i4gets("not_32"), 100, &original_name);      
      delete target;
      return 0;
    }
    else
    {
      w32 buf[256];
      load_palette(basename, original_name, buf);
      w32 pal_id=g1_convert_pal_filename_to_id(basename);

      i4_pixel_format fmt;
      fmt.pixel_depth = I4_8BIT;
      fmt.lookup = buf;

      i4_pal_handle_class pal=i4_pal_man.register_pal(&fmt);
      save_texture((i4_image32 *)im, 0, pal, pal_id, *target);
    }
  }  
#endif

  g1_file_handle han=g1_file_man.get_handle(*target);
  g1_texture_handle th=tmapper.register_texture(han);
  delete target;
  g1_file_man.destroy_handle(han);
  return th;
}



g1_texture_handle convert_flc(const i4_const_str &original_name,
                              const i4_const_str &basename,
                              g1_texture_mapper_class &tmapper)
{
  i4_str *target=i4gets("anim_name").sprintf(100, &basename);

#ifndef G1_RETAIL
  // see if we need to update the texture
  if (target_needs_update(original_name, *target))
  {
    i4_alert(i4gets("updating_anim"),100,&original_name);
    w32 tframes;
    //hacked by trey on 5-23-97 to load a series of .pcx's
    
    w32 buf[256];
    load_palette(basename, original_name, buf);

    i4_pixel_format fmt;
    fmt.pixel_depth = I4_8BIT;
    fmt.lookup = buf;

    i4_pal_handle_class pal=i4_pal_man.register_pal(&fmt);
    w32 pal_id=g1_convert_pal_filename_to_id(basename);
              
    i4_str *path,*bname,*extension;
    i4_str *fname;

    i4_file_man.split_path(original_name,path,bname,extension);
    
    w32 i;
    i = 1;
    i4_file_class *fp;

    while (1)
    {
      
      fname = i4gets("pcx_sequence").sprintf(100,path,bname,i);      
      
      fp = NULL;
      fp = i4_open(*fname);
      if (!fp) {
        delete fname;
        break;
      }

      i4_image_class *im = NULL;

      im=i4_load_image(fp);
      delete fp;
      
      if (im) {                
        i4_str *frame_name=i4gets("anim_frame_name").sprintf(100,&basename,i-1);
        i4_image32 *i32=convert_8_to_32((i4_unmatched_image8 *)im);
        i4_image2  *i2=get_holes((i4_unmatched_image8 *)im);

        save_texture(i32, NULL/*i2*/, pal, pal_id, *frame_name);
        delete frame_name;
        delete im;    
      }
      i++;
      delete fname;
    }
    
    tframes = i-1;
    
    if (path) delete path;
    if (bname) delete bname;
    if (extension) delete extension;

    fp=i4_file_man.open(*target,i4_file_manager_class::WRITE);
    fp->write_8(G1_ANIMATION_FILE);
    fp->write_16(tframes);
    fp->write_counted_str(basename);
    delete fp;    
  }  
#endif

  g1_file_handle han=g1_file_man.get_handle(*target);
  g1_texture_handle th=tmapper.register_texture(han);
  delete target;
  g1_file_man.destroy_handle(han);
  return th;
}


g1_texture_handle convert_name_to_texture(const i4_const_str &name,
                                          g1_texture_mapper_class &tmapper)
{
  if (name.length()==0)
  {
    i4_warning("texture has no name");
    return 0;
  }

  i4_str *path,*basename,*extension;
  i4_str *lower_name=new i4_str(name,name.length()+1);

  i4_file_man.split_path(*lower_name,path,basename,extension);
  basename->to_lower();
  lower_name->to_lower();

  if (path)
    delete path;


  if (extension)
  {
#ifndef G1_RETAIL
    i4_file_status_struct stat;
    if (!i4_file_man.get_status(*lower_name, stat))
    {
      delete lower_name;
      lower_name=i4gets("default_tga").sprintf(150, basename, extension);

      if (!i4_file_man.get_status(*lower_name, stat))
      {
        if (extension) delete extension;
        if (basename) delete basename;
        if (lower_name) delete lower_name;

        i4_alert(i4gets("file_missing"),100,&name);
        return 0;
      }
    }
#endif
    if (*extension==i4gets("flc_ext"))
    { 
      g1_texture_handle ret=convert_flc(*lower_name,*basename,tmapper);
      delete extension;
      delete basename;
      delete lower_name;
      return ret;
    }
    else if (*extension==i4gets("tga_ext"))
    {
      g1_texture_handle ret=convert_tga(*lower_name,*basename,tmapper);
      delete extension;
      delete basename;
      delete lower_name;
      return ret;
    }
  }
  else 
  {
    delete extension;
    delete basename;
    delete lower_name;
    i4_warning("no extension on texture");
    return 0;
  }
  return 0;
}