/*
  Maze editor: world loading
  Copyright (C) 1998 by Jorrit Tyberghein
  Written by Andrew Zabolotny <bit@eltech.ru>

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This library 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
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free
  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <setjmp.h>

#include "sysdef.h"
#include "me_app.h"
#include "me_text.h"
#include "cs3d/common/txtmgr.h"
#include "csengine/thing.h"
#include "csengine/thingtpl.h"
#include "csengine/cssprite.h"
#include "csparser/csloader.h"
#include "csobject/nameobj.h"
#include "csscript/csscript.h" // for LanguageLayer
#include "isystem.h"

static jmp_buf fatal_jmp;

void my_fatal_exit (int errorcode, bool canreturn)
{
  if (!canreturn)
    longjmp (fatal_jmp, errorcode + 1);
}

bool MazeEditor::LoadWorld (char *iFileName)
{
  // Save the world :-)
  System->Printf (MSG_INITIALIZATION, "Number of textures in original world %d\n", world->GetTextures ()->GetNumTextures ());

  //world->Initialize (GetISystemFromSystem (System), System->piGI, config);
  //csWorld *
  new_world = new csWorld();
  LanguageLayer layer (new_world, NULL);
  System->Printf (MSG_INITIALIZATION, "-------------------\n");
  System->Printf (MSG_INITIALIZATION, TEXT_LOADINGWORLDFILE, iFileName);

  void (*old_fatal_exit) (int, bool) = fatal_exit;
  fatal_exit = my_fatal_exit;
  if (setjmp (fatal_jmp))
  {
error:
	System->Printf (MSG_INITIALIZATION, "Fatal error. returning without load\n");
    //We need a different way for that. This won't work on Win32, because 
    //csTextureMM is _not_ linked to MazeD, because csTextureMM is part of the renderers code!
    //csTextureMM::fIgnoreLoadingErrors = false; 
    fatal_exit = old_fatal_exit;
    // Wait three seconds before continuing
    System->Sleep (3000);
    // Restore the world :-)
//    System->world = OldWorld;
    return false;
  }
  //We need a different way for that. This won't work on Win32, because 
  //csTextureMM is _not_ linked to MazeD, because csTextureMM is part of the renderers code!
  //csTextureMM::fIgnoreLoadingErrors = false; 
  void *retc = new_world->OpenWorldFile (/*&layer, */ iFileName);
#if 0
  for (int i = 0; i < world->GetTextures ()->GetNumTextures (); i++)
  {
      new_world->GetTextures()->AddTexture (world->GetTextures ()->GetTextureMM (i));
    } /* endfor */
#endif
  if (!retc)
    goto error;
    if (!CSLoader::LoadWorldFile (new_world, &layer, iFileName))
    {
      System->Printf (MSG_FATAL_ERROR, "Loading of world failed!\n");
      fatal_exit (0, false);
    }
  fatal_exit = old_fatal_exit;
  //We need a different way for that. This won't work on Win32, because 
  //csTextureMM is _not_ linked to MazeD, because csTextureMM is part of the renderers code!
  //csTextureMM::fIgnoreLoadingErrors = false; 

  // Get all textures
  if (world->GetTextures ())
  {
    System->Printf (MSG_INITIALIZATION, TEXT_IMPORTINGTEXTURES);
    System->Printf (MSG_INITIALIZATION, "Number of textures %d\n", new_world->GetTextures ()->GetNumTextures ());
    for (int i = 0; i < new_world->GetTextures ()->GetNumTextures (); i++)
    {
        world->GetTextures()->AddTexture (new_world->GetTextures ()->GetTextureMM (i));
//      world->GetTextures ()->DeleteTexture (0, false);
    } /* endfor */
  } /* endif */

  world->start_sector = strnew(new_world->start_sector);
  world->start_vec = new_world->start_vec;
//   System->Printf (MSG_INITIALIZATION, "start sector %s\n",
//     world->start_sector != 0 ? world->start_sector : "<none>");

  // now load all rooms
  System->Printf (MSG_INITIALIZATION, TEXT_IMPORTINGROOMS);
  int count = new_world->sectors.Length ();
  System->Printf (MSG_INITIALIZATION, "Number of rooms %d\n", world->sectors.Length());
  int no;
  for (no = 0 ; no < count ; no++)
  {
    csSector* sec;
    csThing* thg;

    sec = (csSector *)new_world->sectors [no];
    for (thg = sec->GetFirstThing(); thg!=NULL; thg = (csThing *)thg->GetNext()) {
 //     System->Printf (MSG_INITIALIZATION, "things in sector %d has %s of template %s\n", no, 
//	  csNameObject::GetName(*thg), csNameObject::GetName(*(thg->ParentTemplate)));
      }

    bool done = false;
    for (int i = Models.Length () - 1; i >= 0; i--)
      if (((mz3DModel *)Models [i])->Join ((csSector *)new_world->sectors [no]))
      {
	done = true;
	break;
      }
    if (!done)
    {
        char tname[80];
	// System->Printf (MSG_INITIALIZATION, "Name of rooms %s\n", strcpy(tname, csNameObject::GetName(*p1)));
	mz3DModel *m;
	// distinguish between manual created room and machine generated one
	if (tname[0] == 'o')
	{
		// old six-face model
		CHK ( m = new mz3DModel (csmtRoom, ModelsPath));
	}
	else
	{
		// machine generated one
		CHK ( m = new mz3DModel (csmtSector, ModelsPath));
	}
        Models.Push (m);
	if (!(m->Load ((csSector *)new_world->sectors [no])))
	{
	  System->Printf (MSG_INITIALIZATION,
	  	"Initializing of sector %s fail\n", m->Name);
	  return FALSE;
	}
    }
    world->sectors.Push(new_world->sectors [no]);
  } /* endfor */

  System->Printf (MSG_INITIALIZATION, "Number of new rooms %d\n", world->sectors.Length());
  // now transform world into mz3DModel's
  System->Printf (MSG_INITIALIZATION, TEXT_IMPORTINGTHINGS);
  count = new_world->thing_templates.Length ();
  System->Printf (MSG_INITIALIZATION, "Number of things %d\n", count);
  for (no = 0; no < count; no++)
  {
    CHK (mz3DModel *m = new mz3DModel (csmtThing, ModelsPath));
    CHK (Models.Push (m));
    m->Load ((csThingTemplate *)new_world->thing_templates [no]);
  } /* endfor */

  System->Printf (MSG_INITIALIZATION, TEXT_IMPORTINGSPRITES);
  count = new_world->sprite_templates.Length ();
  System->Printf (MSG_INITIALIZATION, "Number of sprites %d\n", count);
  for (no = 0; no < count; no++)
  {
    csSpriteTemplate *sprite = (csSpriteTemplate *)new_world->sprite_templates [no];
    CHK (mz3DModel *m = new mz3DModel (csmtSprite, ModelsPath));
    CHK (Models.Push (m));
    m->Load (sprite);
    for (int i = 0; i < sprite->GetNumActions (); i++)
    {
      CHK (mzSpriteAction *a = new mzSpriteAction (sprite->GetAction (i)));
      m->InsertAction (a);
    } /* endfor */
  } /* endfor */

  SelectModel (0);
  GLOBAL_FITALL;
  fDraftShowInactiveRooms = TRUE;
  //delete new_world;

#if 0
    csTextureList* t_list = new csTextureList();
    for (int i = 0; i < world->GetTextures ()->GetNumTextures (); i++)
    {
        t_list->AddTexture (world->GetTextures ()->GetTextureMM (i));
//      world->GetTextures ()->DeleteTexture (0, false);
    } /* endfor */

    world->GetTextures ()->Clear();
    for (i = 9; i < t_list->GetNumTextures (); i++)
    {
        world->GetTextures ()->AddTexture (t_list->GetTextureMM (i));
//      world->GetTextures ()->DeleteTexture (0, false);
    } /* endfor */
#endif

//  new_world->Prepare (System->piG3D);

#if 0
  IGraphics3D* g3d = System->piG3D;

  ITextureManager* txtmgr;
  g3d->GetTextureManager (&txtmgr);
  txtmgr->Initialize ();

  // First register all textures to the texture manager.

  for (int i = 0 ; i < new_world->GetTextures()->GetNumTextures () ; i++)
  {
    csTextureHandle* th = new_world->GetTextures()->GetTextureMM (i);
    ITextureHandle* handle;
    txtmgr->RegisterTexture (GetIImageFileFromImageFile (th->GetImageFile ()),
      &handle, th->for_3d, th->for_2d);
    th->SetTextureHandle (handle);
  }

  // Prepare all the textures.
  txtmgr->Prepare (9);

  // Now precalculate some stuff for all loaded polygons.
  for (i = 0 ; i < world->sectors.Length () ; i++)
  {
    csSector* s = (csSector*)new_world->sectors[i];
    s->Prepare ();
  }

  // The images are no longer needed by the 3D engine.
  txtmgr->FreeImages ();

  g3d->ClearCache ();
  new_world->ShineLights ();
  new_world->CreateLightmaps (g3d);

#if defined(OS_NEXT)
// FIXME: NextStep: Multiple Inheritence broken (IID_IHaloRasterizer)
piHR = 0;
#else
//  if (!SUCCEEDED (g3d->QueryInterface(IID_IHaloRasterizer, (void**)&piHR)))
//    piHR = NULL;
#endif

//  ITextureManager* txtmgr;
  System->piG3D->GetTextureManager (&txtmgr);
  if (txtmgr)
  {
    //txtmgr->Prepare (); //fill cause a crash, but looks unnecessary anyway.
    txtmgr->AllocPalette ();
  }
//  SetupPalette ();
#endif
//  SetWorld(new_world);
  // Restore the world :-)
  //world = OldWorld;
//  delete new_world;
  System->Printf (MSG_INITIALIZATION, "Number of textures in final world %d\n", world->GetTextures ()->GetNumTextures ());
  return true;
}
