/**********************************************************************
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) 
***********************************************************************/

#include "tupdate.hh"
#include "loaders/dir_load.hh"
#include "saver_id.hh"
#include "loaders/load.hh"
#include "error/alert.hh"
#include "memory/array.hh"
#include "g1_limits.hh"
#include "status/status.hh"
#include "tex_id.hh"
#include "image/image8.hh"

#include "file/file.hh"
#include "mip.hh"
#include "r1_res.hh"
#include "palette/pal.hh"

extern int m1_max_mip_level;

static i4_str *m1_locate_texture(const i4_const_str &texture_filename)
{
  i4_file_status_struct s;
  i4_str *path, *fname, *ext;

  if (texture_filename.null())
    return 0;

  if (i4_get_status(texture_filename, s))
    return new i4_str(texture_filename);

  i4_filename_struct fn;
  i4_split_path(texture_filename, fn);

  char s_dir[128];
  i4_os_string(r1_gets("s_dir"), s_dir, 128);

  char def_name[256];
  if (fn.extension)
  {
    sprintf(def_name, "%s/%s.%s", s_dir, fn.filename, fn.extension);
    if (i4_get_status(def_name, s))
      return new i4_str(def_name);    
  }

  sprintf(def_name, "%s/%s.jpg", s_dir, fn.filename);
  if (i4_get_status(def_name, s))
    return new i4_str(def_name);    

  return 0;
}



static i4_image_class *m1_convert_8_to_32(i4_image_class *image8)
{
  i4_pixel_format fmt;
  fmt.default_format();

  const i4_pal *pal=i4_pal_man.register_pal(&fmt);
  
  i4_image_class *im8=image8;

  i4_image_class *new32=i4_create_image(im8->width(),
                                        im8->height(),
                                        pal);
  
  w32 *i32=(w32 *)new32->data;
  w8  *i8=(w8 *)im8->data;

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

  w32 i,t=im8->width()*im8->height();
  for (i=0; iget_pal()->source.pixel_depth==I4_8BIT)
  {
    i4_image_class *old = src_texture;    
    src_texture = m1_convert_8_to_32(src_texture);    
    delete old;
  }

  if (src_texture->get_pal()->source.pixel_depth==I4_32BIT)
  {
    /*
    //create a texture update window
    i4_str *update_texture_message = i4gets("updating_texture").sprintf(100,&src_tga);
    
    i4_status_class *status_window = i4_create_status(*update_texture_message);
    
    delete info; //stupid i4 str delete
    */

    char dst_ctext[256];
    i4_os_string(out_ctext,dst_ctext,256);

    char texname[256];
    i4_os_string(src_tga,texname,256);

    //generate the mips    
    result = r1_write_tga_mips(src_texture,dst_ctext,texname,G1_CHROMA_COLOR);
    
    //delete stat; //done making the mips, delete the update window       
  }    

  delete src_texture;

  return result;
}

i4_bool is_newer(const i4_const_str &f1,
                 const i4_const_str &f2)
{
  i4_file_status_struct f1_time, f2_time;

  if (i4_get_status(f1, f1_time))
  {
    if (i4_get_status(f2, f2_time))
      return f1_time.last_modified>f2_time.last_modified;
    else return i4_F;
  }
  else return i4_F;
}

// this function checks the times of the textures with the
// compressed mip version and updates it if it is newer
i4_bool m1_update_texture(const i4_const_str &texture_filename,
                          i4_bool force_all,
                          i4_status_class *stat,
                          float start, float end)
{
  i4_bool ret=i4_F;


  i4_file_status_struct s1,s2; 
  i4_str *tname=m1_locate_texture(texture_filename);
  if (tname)
    {
      if (!force_all)
        i4_get_status(*tname, s1);

      w32 id = r1_get_texture_id(*tname);

      i4_str *texture_file = r1_texture_id_to_filename(id, r1_get_compressed_dir());
    
      ret=i4_T;

      if (force_all)
        {
          m1_pack_mip_texture(*tname,*texture_file);
        }
      else
        {        
          memset(&s1,0,sizeof(i4_file_status_struct));
          memset(&s2,0,sizeof(i4_file_status_struct));
          i4_get_status(*tname, s1);
          i4_get_status(*texture_file, s2);
       
          if (s1.last_modified>s2.last_modified)
            {       
              m1_pack_mip_texture(*tname,*texture_file);
            }
        }


      delete texture_file;
      delete tname;
    } 



  
    return ret;
}

// this calls m1_update_texture on all the textures in an object model file
i4_bool m1_update_object_textures(const i4_const_str &object_filename, 
                                  i4_bool force_all,
                                  const i4_const_str *out_dir)
{

  i4_str *info=i4gets("updating_obj").sprintf(100, &object_filename);
  i4_status_class *stat=i4_create_status(*info);
  delete info;


  i4_bool ret=i4_F;
  i4_file_class *fp=i4_open(object_filename);
  if (fp)
  {
    i4_loader_class *gfp=i4_open_save_file(fp);
    if (gfp)
    {
      if (gfp->goto_section(G1_SECTION_MODEL_TEXTURE_NAMES))
      {
        w16 num_quads = gfp->read_16();
        
        for (int i=0; iread_counted_str(); 
          
          if (m1_update_texture(*texture_name, force_all, stat, 
                                i/(float)num_quads, (i+1)/(float)num_quads))
          {
            ret = i4_T;
          }
          
          delete texture_name;
          
          if (stat)
            stat->update((float)i / (float)num_quads);
        }
      }
      delete gfp;
    }
  }
  else i4_alert(i4gets("obj_missing"),100,&object_filename);

  if (stat)
    delete stat;

  return ret;
}

struct m1_tentry
{
  w32 id;
  w16 first_size;
  w16 w, h;
  w32 ns;
  w8 *data;
  w8 flags;
};

struct m1_tarray
{
  w32 id;
  w16 total;
  w32 *ids;
};

static int id_compare(const m1_tentry *a, const m1_tentry *b)
{
  if (a->id < b->id)
    return -1;
  else if (a->id > b->id)
    return 1;
  else return 0;
}



void m1_convert_all_in_dir(const i4_const_str &dir)
{
  i4_str *info=i4gets("converting_directory").sprintf(100,&dir);
  i4_status_class *stat=i4_create_status(*info);
  delete info;

 
  i4_directory_struct ds;
  if (i4_get_directory(dir, ds))
  {
    for (int i=0; i