/*
  Maze editor: application class
  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.
*/

#ifndef __ME_APP_H__
#define __ME_APP_H__

#include "mazed.h"

/// Rotation and scaling axis/center types
enum mzModificationAxis2D
{
  axUserDefined,
  axTopLeft,
  axTopCenter,
  axTopRight,
  axLeft,
  axCenter,
  axRight,
  axBottomLeft,
  axBottomCenter,
  axBottomRight
};

/// 3D position of modification axis
enum mzModificationAxis3D
{
  axViewPlane,
  axNear,
  axCentered,
  axFar
};

/// Rotation and scaling axis/center structure
struct mzModificationAxis
{
  mzModificationAxis2D Type;	// The 2D location of modification axis
  mzModificationAxis3D Pos;	// The 3D location of modification axis
  bool OnlySelection;		// Consider only selected vertices
  csVector3 Origin;		// Center/origin X, Y and Z
};

/**
 * MazeEditor is a subclass of csApp and implements all top-level functionality
 * of Maze Editor such as manipulating windows, loading/saving models etc.
 */
class MazeEditor : public csApp
{
public:
  /// Static global option variables
  /// Draw coordinate axes on draft view?
  static bool fDraftAxis;
  /// Draw grid on draft vide?
  static bool fDraftGrid;
  /// Snap vertices to grid?
  static bool fSnapToGrid;
  /// Grid spacing (same along all axis)
  static float DraftGridSpacing;
  /// Draw vertices as crosses
  static bool fCrossVertices;
  /// The maximal screen distance (squared) at which points are picked together
  static float DraftPickDist;
  /// Modification axis parameters
  mzModificationAxis Axis;
  /// Draw modification axis on draft views?
  static bool fDraftModificationAxis;
  /// Draw all rooms or only current room/model?
  static bool fDraftShowInactiveRooms;
  /// Number of sides for N-gon
  static int NgonSides;
  /// Number of sides in prism
  static int PrismSides;
  /// Number of sides in pyramid
  static int PyramidSides;
  /// Torus radial detail level
  static int TorusRadialDetail;
  /// Torus cross-section detail level
  static int TorusCrossSectionDetail;
  /// Sphere detail level
  static int SphereDetail;

  /// All models in current scene
  csObjVector Models;
  /// Current model index in Models array
  int CurrentModel;
  /// Current model (just a shortcut to Models [ModelIndex])
  mz3DModel *Model;
  /// twin world for temporary storage of sectors
  csWorld *new_world;

  /// Initialize maze editor
  MazeEditor (int argc, char *argv[]);
  /// Free all resources
  ~MazeEditor ();

  /// Initial setup of Maze Editor
  virtual bool InitialSetup ();

  /// Handle a event
  virtual bool HandleEvent (csEvent &Event);

  /// Set current editing mode; if mode needs args, don't ask if Quiet
  void SetMode (int iMode, bool Quiet);
  /// Query current editing mode
  int GetMode () { return Mode; }

  /// Set current operation description on info pane
  void SetOpDescription (char *iText, ...);
  /// Set specific info field to given string value
  void SetInfo (int id, char *val);
  /// Set specific info field to given numeric value
  void SetInfo (int id, float val);
  /// Set specific info field to given numeric value
  void SetInfo (int id, int val);
  /// Refresh info about current model
  void ModelInfo ();

  /// Query active editing mode (one of cscmdMzCreateVertex etc)
  inline UInt GetEditMode () { return Mode; }

  /// Query active window layout number (0, 1, ...)
  inline UInt GetWindowLayout () { return WindowLayout; }

  /// Query "Vertex" mode selected item
  inline UInt GetVertexMode () { return VertexMode; }
  /// Query "Create 2D" mode selected item
  inline UInt GetCreate2Dmode () { return Create2Dmode; }
  /// Query "Create 3D" mode selected item
  inline UInt GetCreate3Dmode () { return Create3Dmode; }
  /// Query "Create Poly" mode selected item
  inline UInt GetCreatePolyMode () { return CreatePolyMode; }
  /// Query "Select" mode selected item
  inline UInt GetSelectMode () { return SelectMode; }
  /// Query "Modify" mode selected item
  inline UInt GetModifyMode () { return ModifyMode; }

  /// Create a new model of given type and make it current
  void CreateModel (csModelType Type);
  /// Select given model
  void SelectModel (int iNum);
  /// Delete given model
  void DeleteModel (int iIndex);

  /// Ensure that a component fits on desktop; move it if required
  void EnsureFullyVisible (csComponent *comp);

protected:
  /// Override LoadConfig to load user-defined textures
  virtual void LoadConfig ();;

  /// Show and run setup dialog for given action code
  void BarSetupDialog (csButton *Source);

private:
  // friend with draft editor
  friend class mzDraftEditor;
  // friend with draft editor
  friend class mzCameraView;
  // Current editing mode (insert vertex, create box etc etc etc)
  UInt Mode;
  // Last selected "Vertex" submenu item
  UInt VertexMode;
  // Last selected "Create 2D" submenu item
  UInt Create2Dmode;
  // Last selected "Create 3D" submenu item
  UInt Create3Dmode;
  // Last selected "Create Poly" submenu item
  UInt CreatePolyMode;
  // Last selected "Select" submenu item
  UInt SelectMode;
  // Last selected "Modify" submenu item
  UInt ModifyMode;
  // Current window layout number
  UInt WindowLayout;
  // Active button id#
  UInt ActiveButton;
  // World file pathname
  char *WorldName;
  // Default path for 3D models
  char *ModelsPath;
  // Number of windowing system-specific textures
  int ReservedTextures;

  void InitializeApplication ();
  void DefaultLayout ();
  void CloseAllWindows ();
  void Toggle_ToolBox ();
  void Toggle_InfoBox ();
  void Toggle_WindowManager ();
  void Insert_DraftView ();
  void Insert_3DView ();
  void SetWindowLayout (int iNumber);
  void DeleteAllModels ();
  void DeleteAllTextures ();
  bool Load (bool iEntireWorld);
  bool LoadWorld (char *iFileName);
  bool Save (bool iEntireWorld);
  void SetFileName (char *iFileName);
  void ClearModel ();
  bool SetupAxis ();
  void GetUsedTextures (csStrVector &Tex, bool iEntireWorld);
  friend int PolygonInfoDialog (csApp *iApp, mz3DPolygon& sel_poly);

};

// Shortucts to access global option variables
#define F_DRAFT_AXIS			MazeEditor::fDraftAxis
#define F_DRAFT_GRID			MazeEditor::fDraftGrid
#define F_DRAFT_SNAPTOGRID		MazeEditor::fSnapToGrid
#define GLOBAL_DRAFT_GRIDSPACING	MazeEditor::DraftGridSpacing
#define F_DRAFT_CROSSVERTEX		MazeEditor::fCrossVertices
#define GLOBAL_DRAFT_PICKDIST   	MazeEditor::DraftPickDist
#define F_DRAFT_MODIFYAXIS		MazeEditor::fDraftModificationAxis
#define F_DRAFT_SHOWINACTIVEROOMS	MazeEditor::fDraftShowInactiveRooms

// Shortcuts to access some global variables in MazeEditor class
#define GLOBAL_MODELS		(((MazeEditor *)app)->Models)
#define GLOBAL_MODELINDEX	(((MazeEditor *)app)->CurrentModel)
#define GLOBAL_MODEL		(((MazeEditor *)app)->Model)
#define GLOBAL_EDITMODE		(((MazeEditor *)app)->GetEditMode ())
#define GLOBAL_WINDOWLAYOUT	(((MazeEditor *)app)->GetWindowLayout ())
#define GLOBAL_VERTEXMODE	(((MazeEditor *)app)->GetVertexMode ())
#define GLOBAL_CREATE2DMODE	(((MazeEditor *)app)->GetCreate2Dmode ())
#define GLOBAL_CREATE3DMODE	(((MazeEditor *)app)->GetCreate3Dmode ())
#define GLOBAL_CREATEPOLYMODE	(((MazeEditor *)app)->GetCreatePolyMode ())
#define GLOBAL_SELECTMODE	(((MazeEditor *)app)->GetSelectMode ())
#define GLOBAL_MODIFYMODE	(((MazeEditor *)app)->GetModifyMode ())
#define GLOBAL_MODIFYAXIS	(((MazeEditor *)app)->Axis)
#define GLOBAL_NGONSIDES	(((MazeEditor *)app)->NgonSides)
#define GLOBAL_PRISMSIDES	(((MazeEditor *)app)->PrismSides)
#define GLOBAL_PYRAMIDSIDES	(((MazeEditor *)app)->PyramidSides)
#define GLOBAL_TORUSRADIALDETAIL (((MazeEditor *)app)->TorusRadialDetail)
#define GLOBAL_TORUSSECTDETAIL	(((MazeEditor *)app)->TorusCrossSectionDetail)
#define GLOBAL_SPHEREDETAIL	(((MazeEditor *)app)->SphereDetail)

#define GLOBAL_KEY_STATE(key)	System->Keyboard->Key.key

#define GLOBAL_MODELINFO	((MazeEditor *)app)->ModelInfo ()
#define GLOBAL_SETINFO(id,val)	((MazeEditor *)app)->SetInfo (id, val)
#define GLOBAL_SETMODE(id)	(((MazeEditor *)app)->SetMode (id, true))
#define GLOBAL_SETDESC(str)	((MazeEditor *)app)->SetOpDescription (str)
#define GLOBAL_SETDESC1(str,a1)	((MazeEditor *)app)->SetOpDescription (str, a1)
#define GLOBAL_SETDESC2(str,a1,a2)((MazeEditor *)app)->SetOpDescription (str, a1, a2)
#define GLOBAL_SETDESC3(str,a1,a2,a3)((MazeEditor *)app)->SetOpDescription (str, a1, a2, a3)

#define GLOBAL_DRAFTCHANGED						\
  {									\
    csEvent ev (0, (unsigned int)csevBroadcast, (unsigned int)cscmdMzDraftChangeNotify);		\
    app->HandleEvent (ev);						\
  }
#define GLOBAL_DRAFTCHANGED_DELAYED					\
  {									\
    csEvent *ev = new csEvent (0, csevBroadcast, (unsigned int)cscmdMzDraftChangeNotify);\
    app->PutEvent (ev);							\
  }
#define GLOBAL_DESELECTALL						\
  {									\
    GLOBAL_MODEL->SelectAllVertices (cscmdMzVertexDeselectAll);		\
    GLOBAL_MODEL->SelectAllVertices (cscmdMzPolygonDeselectAll);	\
  }
#define GLOBAL_FITALL							\
  {									\
    csEvent ev (0, csevBroadcast, (unsigned int)cscmdMzDraftViewFit);			\
    HandleEvent (ev);							\
  }
#define GLOBAL_FITALL_DELAYED						\
  {									\
    csEvent *ev = new csEvent (0, (unsigned int)csevBroadcast, (unsigned int)cscmdMzDraftViewFit);	\
    app->PutEvent (ev);							\
  }

#endif // __ME_APP_H__
