#include <stdio.h>

//---------------------------------------------------------------------
#include <windows.h>   // required for all Windows applications
#include "resource.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <io.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "cmtw_utils.h"

#include "cmt.h"
#include "cmt_use.h"
#include "cmt_constituent.h"
#include "cmt_generator.h"
#include "cmt_system.h"
#include "cmt_symbol.h"
#include "cmt_tag.h"
#include "cmt_error.h"
//---------------------------------------------------------------------

//---------------------------------------------------------------------
#define USE_THREADS 1
//---------------------------------------------------------------------

//---------------------------------------------------------------------
//
//    Class definitions
//
//---------------------------------------------------------------------

//---------------------------------------------------------------------
class Cmtw;
//---------------------------------------------------------------------

//---------------------------------------------------------------------
class PackageCreator : public WDialog
{
public:
  PackageCreator (Cmtw& cmtw);
  
  int run (HINSTANCE instance, HWND father);
  virtual void action (UINT message_type,
                       WPARAM parameter1,
                       LPARAM parameter2);
  void init_action ();
  void menu_action (int menu_item, WPARAM parameter1, LPARAM parameter2);

private:
  Cmtw& _cmtw;
};
//---------------------------------------------------------------------

//--------------------------------------------------------------------- 
class CMT_Run : public WDialog 
{ 
public: 
  CMT_Run (Cmtw& cmtw); 
   
  int run (HINSTANCE instance, HWND father); 
  void action (UINT message_type, 
               WPARAM parameter1, 
               LPARAM parameter2); 
 
  void init_action (); 
 
  void menu_action (int menu_item, WPARAM parameter1, LPARAM parameter2); 
 
private: 
  Cmtw& _cmtw; 
}; 
//--------------------------------------------------------------------- 
 
//---------------------------------------------------------------------
class ConstituentEditor : public WDialog
{
public:
  ConstituentEditor (cmt_string& line, Cmtw& cmtw);
  
  int run (HINSTANCE instance, HWND father);
  virtual void action (UINT message_type,
                       WPARAM parameter1,
                       LPARAM parameter2);
  void init_action ();
  void menu_action (int menu_item, WPARAM parameter1, LPARAM parameter2);
  
private:
  cmt_string& _line;
  Cmtw& _cmtw;
  WEdit _type;
  WEdit _name;
  WList _modules;
};
//---------------------------------------------------------------------

//---------------------------------------------------------------------
class path_selector : public CmtThread
{
public:
  static path_selector& instance ();
  
  void start (const cmt_string& path);
  void run ();
  
private:
  path_selector ();

  cmt_string _path;
};
//---------------------------------------------------------------------

//---------------------------------------------------------------------
class Cmtw
{
public:
  static Cmtw& instance ();
  BOOL initialize (HINSTANCE instance, HINSTANCE previous_instance, 
                   int show_mode);
  BOOL run ();
  void disable_package_menu_items ();
  void enable_package_menu_items ();
  void do_show_uses ();
  void do_select_path ();
  void do_select_package (const cmt_string& name = "");
  void do_select_version ();
  void do_select_tag (const cmt_string& name);
  void do_config ();
  void do_save_requirements ();
  void do_genmake ();
  void do_genmsdev ();
  void do_build_make_setup ();
  void do_build_constituents_makefile ();
  void do_build_constituent_makefiles ();
  bool is_version (const cmt_string& name);
  void select_package (const cmt_string& path, 
                       const cmt_string& package);
  void select_path (const cmt_string& path,
                    const cmt_string& prefix = "", 
                    int level = 0);
  int show_tags (HWND window, int x, int y, cmt_string& selected_name);
  
  const char* _application_name;
  const char* _title;

  HINSTANCE _instance;
  HWND _window;

  HWND _the_dialog;

  WList _path_list;
  WList _package_list;
  WEdit _package;
  WList _version_list; 

  WList _requirements; 
 
  WList _show_uses;
  WList _show_constituents;
  WList _show_macros;
  WList _show_sets;
  WList _output; 
 
  WRadio _set_uses; 
  WRadio _set_constituents; 
  WRadio _set_macros; 
  WRadio _set_sets; 
  WRadio _set_output; 
 
  WTab  _tab;
  WEdit _tag; 
  CmtMutex dir_mutex;

private:

  Cmtw ();

  static LRESULT CALLBACK process_messages (HWND window,
                                            UINT message_type,
                                            WPARAM parameter1,
                                            LPARAM parameter2);
  static LRESULT CALLBACK handle_dialog (HWND dialog,
                                         UINT message_type,
                                         WPARAM parameter1,
                                         LPARAM parameter2);
  
  HANDLE* _objects;
  int _object_count;
};
//---------------------------------------------------------------------



//---------------------------------------------------------------------
int APIENTRY WinMain (HINSTANCE instance,
                      HINSTANCE previous_instance,
                      LPSTR command_line,
                      int show_mode)
//---------------------------------------------------------------------
{                
  Cmtw& cmtw = Cmtw::instance ();

  cmtw.initialize (instance, previous_instance, show_mode);

  return cmtw.run ();

  UNREFERENCED_PARAMETER (command_line);

  return (0);
}



//---------------------------------------------------------------------
//
//    Class implementations
//
//---------------------------------------------------------------------

//---------------------------------------------------------------------
PackageCreator::PackageCreator (Cmtw& cmtw) : _cmtw (cmtw)
{
}

int PackageCreator::run (HINSTANCE instance, HWND father)
{
  return (WDialog::run (instance, father, IDD_NEWPACKAGE));
}

void PackageCreator::action (UINT message_type,
                             WPARAM parameter1,
                             LPARAM parameter2)
{
}

void PackageCreator::init_action ()
{
  WList list (_dialog, IDNP_PATHLIST);
  
  list.copy (_cmtw._path_list);
}

void PackageCreator::menu_action (int menu_item, 
                                  WPARAM parameter1, 
                                  LPARAM parameter2)
{
  switch (menu_item) 
    {
    case IDOK:
      {
        WList list (_dialog, IDNP_PATHLIST);
        WEdit p (_dialog, IDNP_PACKAGE);
        WEdit v (_dialog, IDNP_VERSION);
        WEdit pr (_dialog, IDNP_PREFIX);
        
        cmt_string path = list.get_selected ();
        cmt_string package = p.get ();
        cmt_string version = v.get ();
        cmt_string prefix = pr.get ();

        mysb s (_cmtw._output);
        cout << "cmt config " << package << " " <<
          version << " " << 
          path << " " <<
          prefix << endl;

        if ((package != "") &&
            (version != ""))
          {
            if (prefix != "")
              { 
				if (path != "") 
				{
                  path += CmtSystem::file_separator (); 
				}
                path += prefix;
              } 
			Cmt::configure ();
            Cmt::do_create (package, version, path);
          }
      }
      break;
    case IDCANCEL:
      break;
    default:
      break;
    }
}
//---------------------------------------------------------------------

//--------------------------------------------------------------------- 
CMT_Run::CMT_Run (Cmtw& cmtw) : _cmtw (cmtw) 
{ 
} 
 
int CMT_Run::run (HINSTANCE instance, HWND father) 
{ 
  return (WDialog::run (instance, father, IDD_CMT)); 
} 
 
void CMT_Run::action (UINT message_type, 
                      WPARAM parameter1, 
                      LPARAM parameter2) 
{ 
} 
 
void CMT_Run::init_action () 
{ 
} 
 
void CMT_Run::menu_action (int menu_item,  
                           WPARAM parameter1,  
                           LPARAM parameter2) 
{ 
  switch (menu_item)  
    { 
    case IDCMT_EXECUTE: 
		{ 
			WEdit command (_dialog, IDCMT_COMMAND); 
			WList output (_dialog, IDCMT_OUTPUT); 
			 
			cmt_string c = "cmt "; 
			c += command.get (); 
 
			output.clear (); 
			{ 
				mysb s (output); 
				cout << c << endl; 
				Cmt::parser (c); 
			} 
		} 
      break; 
    case IDCANCEL: 
      break; 
    default: 
      break; 
    } 
} 
//--------------------------------------------------------------------- 
 
//---------------------------------------------------------------------
path_selector& path_selector::instance ()
{
  static path_selector the_instance;

  return (the_instance);
}

path_selector::path_selector ()
{
}

void path_selector::start (const cmt_string& path)
{
  Cmtw& cmtw = Cmtw::instance ();

  if (is_running ()) 
    {
      {
        mysb s (cmtw._output);
        cout << "Path selector already running. Please retry later..." << endl;
      }
      return;
    }

  _path = path;
  CmtThread::start ();
}

void path_selector::run ()
{
  Cmtw& cmtw = Cmtw::instance ();

  cmtw._package_list.clear ();
  cmtw._version_list.clear ();
  cmtw._requirements.clear ();
  cmtw._show_uses.clear ();
  cmtw._show_constituents.clear ();
  cmtw._tag.clear ();
  cmtw._show_macros.clear ();
  cmtw._show_sets.clear ();
  cmtw._output.clear ();

  {
    mysb s (cmtw._output);
    cout << "Path selector started." << endl;
  }

  cmtw.disable_package_menu_items ();

  cmtw.select_path (_path);

  {
    mysb s (cmtw._output);
    cout << "Path selector terminated." << endl;
  }

}
//---------------------------------------------------------------------

//---------------------------------------------------------------------
ConstituentEditor::ConstituentEditor (cmt_string& line, Cmtw& cmtw) : 
        _line (line), _cmtw (cmtw)
{
}

int ConstituentEditor::run (HINSTANCE instance, HWND father)
{
  return (WDialog::run (instance, father, IDD_CONSTITUENT));
}

void ConstituentEditor::action (UINT message_type,
                                WPARAM parameter1,
                                LPARAM parameter2)
{
}

void ConstituentEditor::init_action ()
{
  _type.init (_dialog, IDCE_TYPE);
  _name.init (_dialog, IDCE_NAME);
  _modules.init (_dialog, IDCE_MODULES);

  CmtSystem::cmt_string_vector words;
  
  CmtSystem::split (_line,  " ", words);

  if (words.size () >= 2)
    {
      const cmt_string& t = words[0];
      if ((t == "library") ||
          (t == "application"))
        {
          const cmt_string& name = words[1];

          Constituent* constituent = Constituent::find (name);
          if (constituent != 0)
            {
              _type.set (t);
              _name.set (name);
              _modules.set (constituent->modules);
            }
        }
    }
}

void ConstituentEditor::menu_action (int menu_item, 
                                     WPARAM parameter1, 
                                     LPARAM parameter2)
{
  switch (menu_item) 
    {
    case IDOK:
      break;
    case IDCANCEL:
      break;
    case IDCE_MODULES:
      if (HIWORD (parameter1) == LBN_DBLCLK)
        {
          cmt_string file_name = _modules.get_selected ();
          cmt_string line = Generator::build_dependencies (file_name);

          mysb sb (_cmtw._output);
          cout << line << endl;
        }
      break;
    case IDCE_EDITMODULES:
      {
        ListEditor editor (_modules);
        editor.run (_cmtw._instance, _dialog);
      }
      break;
    default:
      break;
    }
}
//---------------------------------------------------------------------

//---------------------------------------------------------------------
Cmtw& Cmtw::instance ()
{
  static Cmtw the_instance;
  
  return (the_instance);
}

BOOL Cmtw::initialize (HINSTANCE instance, HINSTANCE previous_instance, 
                       int show_mode)
{
  WNDCLASS  window_class;
  
  // Fill in window class structure with parameters that describe the
  // main window.
  
  if (!previous_instance) 
    {
      window_class.style         = CS_OWNDC;
      window_class.lpfnWndProc   = (WNDPROC) process_messages;
      window_class.cbClsExtra    = 0;
      window_class.cbWndExtra    = 0;
      window_class.hInstance     = instance;
      window_class.hIcon         = LoadIcon (instance, _application_name);
      window_class.hCursor       = LoadCursor (NULL, IDC_ARROW);
      window_class.hbrBackground = (HBRUSH) (COLOR_MENU+1);
      window_class.lpszMenuName  = "TEXTFXMENU";
      window_class.lpszClassName = _application_name;
      
      if (!RegisterClass (&window_class)) return (FALSE);
    }
  
  _instance = instance;
  
  _window = CreateWindow (_application_name,
                          _title,
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, 0, 440, 590,
                          NULL,
                          NULL,
                          _instance,
                          NULL);
  
  // If window could not be created, return "failure"
  
  if (!_window)
    {
      return (FALSE);
    }
  
  ShowWindow (_window, show_mode);
  UpdateWindow (_window);
  
  return (TRUE);
}

BOOL Cmtw::run ()
{
  MSG message;
  DWORD result;
  HANDLE objects[1];
  int count = 0;

  while (TRUE)
    {
      result = MsgWaitForMultipleObjects (count, objects, FALSE, 
                                          INFINITE, QS_ALLINPUT);
      if (result == (WAIT_OBJECT_0 + count))
        {
          while (PeekMessage (&message, NULL, 0, 0, PM_REMOVE))
            {
              if ((_the_dialog == NULL) ||
                  !IsDialogMessage (_the_dialog, &message))
                {
                  if (!TranslateAccelerator (message.hwnd, NULL, &message))
                    {
                      if (message.message == WM_QUIT) return (0);

                      TranslateMessage (&message);
                      DispatchMessage (&message);
                    }
                }
            }
        }
      else
        {
          // For future async objects
        }
    }
                
  return (message.wParam);
}

void Cmtw::disable_package_menu_items ()
{
  HMENU menu = GetMenu (_window);
  EnableMenuItem (menu, IDM_CONFIG, MFS_GRAYED | MF_BYCOMMAND);
  EnableMenuItem (menu, IDM_GENMAKE, MFS_GRAYED | MF_BYCOMMAND);
  EnableMenuItem (menu, IDM_GENMSDEV, MFS_GRAYED | MF_BYCOMMAND);
  EnableMenuItem (menu, IDM_BUILDSETUP, MFS_GRAYED | MF_BYCOMMAND);
  EnableMenuItem (menu, IDM_BUILDCONSTITUENTSMAKEFILE, 
                  MFS_GRAYED | MF_BYCOMMAND);
  EnableMenuItem (menu, IDM_BUILDCONSTITUENTMAKEFILE, 
                  MFS_GRAYED | MF_BYCOMMAND);

  _show_uses.disable ();
  _show_constituents.disable ();
  _show_macros.disable ();
  _show_sets.disable ();
  _requirements.disable ();
}
                        
void Cmtw::enable_package_menu_items ()
{
  HMENU menu = GetMenu (_window);
  EnableMenuItem (menu, IDM_CONFIG, MFS_ENABLED | MF_BYCOMMAND);
  EnableMenuItem (menu, IDM_GENMAKE, MFS_ENABLED | MF_BYCOMMAND);
  EnableMenuItem (menu, IDM_GENMSDEV, MFS_ENABLED | MF_BYCOMMAND);
  EnableMenuItem (menu, IDM_BUILDSETUP, MFS_ENABLED | MF_BYCOMMAND);
  EnableMenuItem (menu, IDM_BUILDCONSTITUENTSMAKEFILE, 
                  MFS_ENABLED | MF_BYCOMMAND);
  EnableMenuItem (menu, IDM_BUILDCONSTITUENTMAKEFILE, 
                  MFS_GRAYED | MF_BYCOMMAND);

  _show_uses.enable ();
  _show_constituents.enable ();
  _show_macros.enable ();
  _show_sets.enable ();
  _requirements.enable ();
}
                        
void Cmtw::do_show_uses ()
{
  mysb s (_show_uses);
  Use::show_all ();
}
  
void Cmtw::do_select_path ()
{
  cmt_string path = _path_list.get_selected ();

  path_selector& selector = path_selector::instance ();
      
#ifdef USE_THREADS
  selector.start (path);
#else
  {
    mysb s (_output);
    cout << "running thread "<< endl;
  }
      
  _package_list.clear ();
  _version_list.clear ();
  _requirements.clear ();
  _show_uses.clear ();
  _show_constituents.clear ();
  _tag.clear ();
  _show_macros.clear ();
  _show_sets.clear ();
  _output.clear ();
      
  disable_package_menu_items ();
      
  select_path (path);
#endif
}
  
void Cmtw::do_select_package (const cmt_string& name)
{
  _requirements.clear ();
  _show_uses.clear ();
  _show_constituents.clear ();
  _tag.clear ();
  _show_macros.clear ();
  _show_sets.clear ();
  _output.clear ();
      
  disable_package_menu_items ();
      
  cmt_string path;
  cmt_string package;
      
  path = _path_list.get_selected ();
      
  if (name == "") package = _package_list.get_selected ();
  else package = name;
      
  select_package (path, package);
}
  
void Cmtw::do_select_version ()
{
  cmt_string path;
  cmt_string package;
  cmt_string version;
  bool ok;
      
  path = _path_list.get_selected ();
      
  package = _package.get ();
  if (package == "") package = _package_list.get_selected ();
      
  version = _version_list.get_selected ();
      
  _requirements.clear ();
  _tag.clear ();
  _show_uses.clear ();
  _show_constituents.clear ();
  _show_macros.clear ();
  _show_sets.clear ();
  _output.clear ();
      
  if (version == "")
    {
      mysb s (_output);
      cout << "Please select a version first" << endl;
      return;
    }
      
  {
    mysb s (_output);
    ok = Cmt::load (path, package, version);
    _requirements.set ("requirements");
  }

  if (!ok)
  {
    mysb s (_output);
	CmtError::print ();
  }
  else
  { 
  {
    mysb s (_output);
    Cmt::set_standard_macros ();
  }
      
  {
    mysb s (_show_uses);
	Cmt::action = action_show_uses;   
	Cmt::quiet = false; 
    Use::show_all ();
  }
  { 
    mysb s (_show_constituents);
	Cmt::action = action_show_constituents; 
	Cmt::quiet = true; 
    Constituent::show_all ();
  } 
  { 
    mysb s (_show_macros); 
	Cmt::action = action_show_macros;
    Cmt::print_macros (Csh);
  } 
  { 
    mysb s (_show_sets); 
	Cmt::action = action_show_sets;
    Cmt::print_macros (Csh);
  } 
  { 
    Symbol* symbol = Symbol::find ("tag");
    if (symbol != 0)
      { 
        const cmt_string tag = symbol->build_macro_value ();
        _tag.set (tag);
      } 
  } 
  }
  enable_package_menu_items ();
}
  
void Cmtw::do_select_tag (const cmt_string& name)
{
  cmt_string path;
  cmt_string package;
  cmt_string version;
  bool ok;
      
  path    = _path_list.get_selected ();
      
  package = _package.get ();
  if (package == "") package = _package_list.get_selected ();
      
  version = _version_list.get_selected ();
      
  _show_macros.clear ();
  {
    mysb s (_output);
    ok = Cmt::load (path, package, version, name);
  }
  if (!ok) return;
      
  Cmt::quiet = true; 
  Cmt::set_standard_macros ();
      
  {
    mysb s (_show_macros);
    Cmt::print_macros (Csh);
  }
}
  
void Cmtw::do_config ()
{
  mysb s (_output);
  Cmt::do_config ();
}
  
void Cmtw::do_save_requirements ()
{
  cmt_string text;
      
  _requirements.get (text);
      
  FILE* f = fopen ("requirements", "wb");
  if (f != NULL)
    {
      text.write (f);
      fclose (f);
    }
}
  
void Cmtw::do_genmake ()
{
  cmt_string line = _show_constituents.get_selected ();
  CmtSystem::cmt_string_vector words;
  
  CmtSystem::split (line, " ", words);
      
  if (words.size () >= 2)
    {
      const cmt_string& t = words[0];
      if ((t == "library") ||
          (t == "application"))
        {
          const cmt_string& name = words[1];
              
          mysb s (_output);
          Cmt::build_makefile (name);
        }
    }
  else
    {
      mysb s (_output);
      Cmt::build_makefile ("");
    }
}
  
void Cmtw::do_genmsdev ()
{
  cmt_string line = _show_constituents.get_selected ();
  CmtSystem::cmt_string_vector words;
  
  CmtSystem::split (line, " ", words);
      
  if (words.size () >= 2)
    {
      const cmt_string& t = words[0];
      if ((t == "library") ||
          (t == "application"))
        {
          const cmt_string& name = words[1];
              
          mysb s (_output);
          Cmt::build_msdev_file (name);
        }
    }
  else
    {
      mysb s (_output);
      Cmt::build_msdev_file ("");
    }
}
  
void Cmtw::do_build_make_setup ()
{
  cmt_string package = _package_list.get_selected ();
  cmt_string version = _version_list.get_selected ();
      
  if ((package != "") && (version != ""))
    {
      mysb s (_output);
      Generator::build_make_setup (package);
    }
}
  
void Cmtw::do_build_constituents_makefile ()
{
  cmt_string package = _package_list.get_selected ();
  cmt_string version = _version_list.get_selected ();
      
  if ((package != "") && (version != ""))
    {
      mysb s (_output);
      Generator::build_constituents_makefile (package);
    }
}
  
void Cmtw::do_build_constituent_makefiles ()
{
  cmt_string package;
  cmt_string version;
      
  package = _package_list.get_selected ();
  if (package == "") package = _package.get ();
      
  version = _version_list.get_selected ();
      
  if ((package != "") && (version != ""))
    {
      cmt_string line = _show_constituents.get_selected ();
      CmtSystem::cmt_string_vector words;
	  
	  CmtSystem::split (line, " ", words);
          
      if (words.size () >= 2)
        {
          const cmt_string& t = words[0];
          if ((t == "library") ||
              (t == "application"))
            {
              int i;
                  
              const cmt_string& name = words[1];
              mysb s (_output);
              Generator::build_constituent_makefile (name);
                  
              for (i = 2; i < words.size (); i++)
                {
                  const cmt_string& module = words[i];
                  Generator::build_dependencies (module);
                }
            }
        }
    }
}
  
bool Cmtw::is_version (const cmt_string& name)
{
  const cmt_string numbers = "0123456789";
  const int starting  = 0;
  const int at_key    = 1;
  const int at_number = 2;

  int state = starting;
  int pos;
  
  for (pos = 0; pos < name.size (); pos++)
    {
      char c = name[pos];

      if (numbers.find (c) == cmt_string::npos)
        {
          switch (state)
            {
              case starting:
                state = at_key;
                break;
              case at_key:
                return (false);
              case at_number:
                state = at_key;
                break;
            }
        }
      else
        {
          switch (state)
            {
              case starting:
                return (false);
              case at_key:
                state = at_number;
                break;
              case at_number:
                break;
            }
        }
    }
  
  return ((state == at_number));
}
  
void Cmtw::select_package (const cmt_string& path, 
                           const cmt_string& package)
{
    //
    // Only do something if it is a directory.
    //

  _version_list.clear ();
      
  bool test;

  cmt_string pattern = path;
  pattern += CmtSystem::file_separator ();
  pattern += package;

  /*
  {
    mysb sb (_output);
    cout << "scan> testing directory pattern=" << pattern << endl;
  }
  */

  dir_mutex.lock ();
  test = CmtSystem::test_directory (pattern);
  dir_mutex.unlock ();
  if (!test) return;

    //
    // The scan_dir requests a pattern <dir>/<name> to scan <dir>
    //

  pattern += CmtSystem::file_separator ();
  pattern += "*";

  CmtSystem::cmt_string_vector list;

  dir_mutex.lock ();
  CmtSystem::scan_dir (pattern, list);
  dir_mutex.unlock ();

  if (list.size () == 0) return;

  int i;
  for (i = 0; i < list.size (); i++)
    {
      const cmt_string& name = list[i];

      /*
      {
        mysb sb (_output);
        cout << "scan10> name=" << name;
      }
      */

      cmt_string version;
      CmtSystem::basename (name, version);

      if (is_version (version))
        {
          cmt_string req;

          req = name;
          req += CmtSystem::file_separator ();
          req += "cmt";
          req += CmtSystem::file_separator ();
          req += "requirements";

          dir_mutex.lock ();
          test = CmtSystem::test_file (req);
          dir_mutex.unlock ();
          if (test)
            {
              _version_list.append (version);
            }
          else
            {
              req = name;
              req += CmtSystem::file_separator ();
              req += "mgr";
              req += CmtSystem::file_separator ();
              req += "requirements";

              dir_mutex.lock ();
              test = CmtSystem::test_file (req);
              dir_mutex.unlock ();
              if (test)
			  {
                 _version_list.append (version);
			  }
            }
        }
      else
        {
          /*
          {
            mysb sb (_output);
            cout << " -> stop" << endl;
          }
          */
        }
    }
}

void Cmtw::select_path (const cmt_string& path, 
                        const cmt_string& prefix, 
                        int level)
{
  long handle = 0;
    //
    // Only do something if it is a directory.
    //

  cmt_string full_path = path;
  if (prefix != "")
    {
      full_path += CmtSystem::file_separator ();
      full_path += prefix;
    }

  if (full_path[full_path.size () -1] == ':')
    {
      full_path += CmtSystem::file_separator ();
    }

  /*
  {
    mysb sb (_output);
    cout << "scan> testing directory " << full_path << endl;
  }
  */

  bool test;

  dir_mutex.lock ();
  test = CmtSystem::test_directory (full_path);
  dir_mutex.unlock ();
  if (!test) return;

    //
    // The scan_dir requests a pattern <dir>/<name> to scan <dir>
    //
  cmt_string pattern = full_path;
  pattern += CmtSystem::file_separator ();
  pattern += "*";

  CmtSystem::cmt_string_vector list;

  dir_mutex.lock ();
  CmtSystem::scan_dir (pattern, list);
  dir_mutex.unlock ();

  if (list.size () == 0) return;

    // Will be set if at least one directory is a version directory
  bool has_package = false;
      
  cmt_string pack;
  CmtSystem::basename (full_path, pack);

  int i;
  for (i = 0; i < list.size (); i++)
    {
      const cmt_string& name = list[i];

      /*
      {
        mysb sb (_output);
        cout << "scan8> level=" << level << " name=" << name;
      }
      */

      cmt_string version;
      CmtSystem::basename (name, version);

        //
        //  All entries at this level may be "legal" version directories.
        //
        //  So we go down but no more then one level deep.
        //  The next level we request that the entry is a version
        //  and that there is a mgr/requirements file below.
        //

      if (level == 0)
        {
          /*
          {
            mysb sb (_output);
            cout << " -> down" << endl;
          }
          */

          cmt_string p = "";

          if (prefix != "")
            {
              p += prefix;
              p += CmtSystem::file_separator ();
            }

          p += version;

          select_path (path, p, level + 1);
        }
      else if (is_version (version))
        {
          cmt_string req;

          req = name;
          req += CmtSystem::file_separator ();
          req += "cmt";
          req += CmtSystem::file_separator ();
          req += "requirements";

          dir_mutex.lock ();
          test = CmtSystem::test_file (req);
          dir_mutex.unlock ();
          if (test)
            {
              /*
              {
                mysb sb (_output);
                cout << " -> mgr" << endl;
                cout << pack << " " << version << " " << full_path << endl;
              }
              */

              has_package = true;

              break;
            }
          else
            {
              req = name;
              req += CmtSystem::file_separator ();
              req += "mgr";
              req += CmtSystem::file_separator ();
              req += "requirements";

              dir_mutex.lock ();
              test = CmtSystem::test_file (req);
              dir_mutex.unlock ();
              if (test)
			  {
                has_package = true;

                break;
			  }
            }
        }
      else
        {
          /*
          {
            mysb sb (_output);
            cout << " -> stop" << endl;
          }
          */
        }
    }

  if (has_package)
    {
        //
        // At least one version was found here.
        //

      _package_list.append (prefix);

      select_path (path, prefix, 0);
    }
}
  
int Cmtw::show_tags (HWND window, int x, int y, cmt_string& selected_name)
{
  const Tag::TagPtrVector& tags = Tag::tags ();
      
  int selected;
      
  HMENU menu = CreatePopupMenu ();
      
  for (int i = 0; i < tags.size (); i++)
    {
      Tag* tag = tags[i];
          
      if (tag != 0)
        {
          AppendMenu (menu, MFT_STRING, IDM_FIRSTTAG + i, 
                      tag->name.c_str ());
        }
    }
      
  selected = (int) TrackPopupMenu (menu, TPM_TOPALIGN | 
                                   TPM_LEFTALIGN | 
                                   TPM_RETURNCMD, 
                                   x, y, 0, window, NULL);
      
  if (selected >= IDM_FIRSTTAG)
    {
      char name[80];
          
      GetMenuString (menu, selected - IDM_FIRSTTAG, name, sizeof (name), 
                     MF_BYPOSITION);
          
      selected_name = name;
          
      _tag.set (selected_name);
          
      do_select_tag (selected_name);
    }
      
  return (selected);
}

Cmtw::Cmtw () : _application_name ("CMTW"), _title ("CMTW Test Application")
{
  _the_dialog = 0;
  _objects = 0;
  _object_count = 0;
}

LRESULT CALLBACK Cmtw::process_messages (HWND window,
                                         UINT message_type,
                                         WPARAM parameter1,
                                         LPARAM parameter2)
{
  Cmtw& cmtw = Cmtw::instance ();
      
  int menu_item;
  static HPEN blue_pen;
  static HPEN red_pen;
      
  SetLastError (0);
      
  switch (message_type) 
    {         
    case WM_CREATE:
      {
        HDC context;
        LOGFONT log_font;
        HFONT font;
            
        context = GetDC (window);
            
        memset (&log_font, 0, sizeof(LOGFONT));
        log_font.lfHeight = -72;
        strcpy ((LPSTR) &(log_font.lfFaceName), "arial");
            
        font = CreateFontIndirect (&log_font); 
        SelectObject (context, font);
            
        blue_pen = CreatePen (PS_SOLID, 1, RGB(0,0,255));
        red_pen  = CreatePen (PS_SOLID, 1, RGB(255,0,0));
      }
          
      cmtw._window = window;
          
      cmtw._the_dialog = CreateDialog (cmtw._instance, 
                                       MAKEINTRESOURCE(IDD_DIALOGBAR), 
                                       window,
                                       (DLGPROC) handle_dialog);
          
      cmtw.disable_package_menu_items ();
          
      break;
          
    case WM_COMMAND:
      menu_item = LOWORD (parameter1);
          
      switch (menu_item) 
        {
        case IDM_EXIT:
          DestroyWindow (window);
          break;
        case IDM_CONFIG:
          cmtw.do_config ();
          break;
        case IDM_GENMAKE:
          cmtw.do_genmake ();
          break;
        case IDM_GENMSDEV:
          cmtw.do_genmsdev ();
          break;
        case IDM_BUILDSETUP:
          cmtw.do_build_make_setup ();
          break;
        case IDM_BUILDCONSTITUENTSMAKEFILE:
          cmtw.do_build_constituents_makefile ();
          break;
        case IDM_BUILDCONSTITUENTMAKEFILE:
          cmtw.do_build_constituent_makefiles ();
          break;
        case IDM_NEWPACKAGE:
          {
            PackageCreator creator (cmtw);
                
            creator.run (cmtw._instance, window);
          }
          break;
        case IDM_CMT: 
          { 
            CMT_Run cmt (cmtw); 
                 
            cmt.run (cmtw._instance, window); 
          } 
          break; 
        default:
          return (DefWindowProc (window, message_type, 
                                 parameter1, parameter2));
        }
      break;
    case WM_DESTROY:
      PostQuitMessage (0);
      break;
    default:
      return (DefWindowProc (window, message_type, parameter1, parameter2));
    }
  return (0);
}
  
LRESULT CALLBACK Cmtw::handle_dialog (HWND dialog,
                                      UINT message_type,
                                      WPARAM parameter1,
                                      LPARAM parameter2)
{
  Cmtw& cmtw = Cmtw::instance ();
      
  int menu_item;
      
  switch (message_type) 
    {
    case WM_CREATE:
      break;
    case WM_SETFONT:
      break;
    case WM_INITDIALOG:
      {
        int x = 0;
        int y = 0;
        int width;
        int height;
        RECT rectangle;
            
        GetWindowRect (dialog, &rectangle);
            
        width = rectangle.right - rectangle.left;
        height = rectangle.bottom - rectangle.top;
            
        MoveWindow (cmtw._window, x, y, width, height, TRUE);
      }
          
      cmtw._path_list.init (dialog, IDM_PATHLIST);
      cmtw._package_list.init (dialog, IDM_PACKAGELIST);
      cmtw._package.init (dialog, IDM_PACKAGE);
      cmtw._version_list.init (dialog, IDM_VERSIONLIST); 

      cmtw._requirements.init (dialog, IDM_REQUIREMENTS); 
 
      cmtw._show_uses.init (dialog, IDM_USES);
      cmtw._show_constituents.init (dialog, IDM_CONSTITUENTS);
      cmtw._show_macros.init (dialog, IDM_MACROS);
      cmtw._show_sets.init (dialog, IDM_SETS);
      cmtw._output.init (dialog, IDM_OUTPUT); 
 
      cmtw._set_uses.init (dialog, IDM_SETUSES); 
      cmtw._set_constituents.init (dialog, IDM_SETCONSTITUENTS); 
      cmtw._set_macros.init (dialog, IDM_SETMACROS); 
      cmtw._set_sets.init (dialog, IDM_SETSETS); 
      cmtw._set_output.init (dialog, IDM_SETOUTPUT); 
 
      cmtw._tag.init (dialog, IDM_TAG); 
 
	  cmtw._tab.add ("uses",          
		  cmtw._show_uses,  
		  cmtw._set_uses); 
	  cmtw._tab.add ("constituents",  
		  cmtw._show_constituents, 
		  cmtw._set_constituents); 
	  cmtw._tab.add ("macros",        
		  cmtw._show_macros, 
		  cmtw._set_macros); 
	  cmtw._tab.add ("sets",        
		  cmtw._show_sets, 
		  cmtw._set_sets); 
	  cmtw._tab.add ("output",        
		  cmtw._output, 
		  cmtw._set_output); 
	   
	  cmtw._tab.select ("uses"); 
 
      { 
        CmtSystem::cmt_string_vector paths;
        CmtSystem::cmt_string_vector path_sources;

        CmtSystem::get_cmt_paths (paths, path_sources);
            
        cmtw._path_list.set (paths);
      } 
          
      break;
    case WM_COMMAND:
      menu_item = LOWORD (parameter1);
          
      switch (menu_item) 
        {
        case IDM_PATHLIST:
          if (HIWORD (parameter1) == LBN_DBLCLK)
            {
              cmtw.do_select_path ();
            }
          break;
        case IDM_PACKAGELIST:
          if (HIWORD (parameter1) == LBN_DBLCLK)
            {
              cmtw.do_select_package ();
            }
          break;
        case IDM_PACKAGE:
          { 
            cmt_string name = cmtw._package.get ();
            cmtw.do_select_package (name);
          } 
          break;
        case IDM_VERSIONLIST:
          if (HIWORD (parameter1) == LBN_DBLCLK)
            {
              cmtw.do_select_version ();
            }
          break;
        case IDM_USES:
          break;
        case IDM_CONSTITUENTS:
          if (HIWORD (parameter1) == LBN_DBLCLK)
            {
              cmt_string line = cmtw._show_constituents.get_selected ();
              ConstituentEditor editor (line, cmtw);
                  
              editor.run (cmtw._instance, dialog);
            }
          else
            {
              cmt_string line = cmtw._show_constituents.get_selected ();
                  
              HMENU menu = GetMenu (cmtw._window);
                  
              if (line == "")
                {
                  EnableMenuItem (menu, IDM_BUILDCONSTITUENTMAKEFILE, 
                                  MFS_GRAYED | MF_BYCOMMAND);
                }
              else
                {
                  EnableMenuItem (menu, IDM_BUILDCONSTITUENTMAKEFILE, 
                                  MFS_ENABLED | MF_BYCOMMAND);
                }
            }
          break;
        case IDM_TAG:
          {
            int x = 0;
            int y = 0;
            RECT rectangle;
                
            GetWindowRect (GetDlgItem (dialog, IDM_TAG), &rectangle);
            x = rectangle.left;
            y = rectangle.top;
                
            cmt_string name (80);
            int selected = cmtw.show_tags (dialog, x, y, name);
          } 
          break;
        case IDM_SETUSES: 
			cmtw._tab.select ("uses"); 
          break; 
        case IDM_SETMACROS: 
			cmtw._tab.select ("macros"); 
          break; 
        case IDM_SETSETS: 
			cmtw._tab.select ("sets"); 
          break; 
        case IDM_SETCONSTITUENTS: 
			cmtw._tab.select ("constituents"); 
          break; 
        case IDM_SETOUTPUT: 
			cmtw._tab.select ("output"); 
          break; 
        case IDM_MACROS:
          if (HIWORD (parameter1) == LBN_DBLCLK)
            {
              cmt_string line = cmtw._show_macros.get_selected ();
              mysb s (cmtw._output);
              cout << line << endl;
            }
          break;
        case IDM_REQUIREMENTS:
          if (HIWORD (parameter1) == LBN_DBLCLK)
            {
              ListEditor editor (cmtw._requirements);
                  
              editor.run (cmtw._instance, dialog);
            }
          break;
        case IDM_EDITREQUIREMENTS:
          {
            ListEditor editor (cmtw._requirements);
                
            editor.run (cmtw._instance, dialog);
          } 
          break;
        case IDM_SAVEREQUIREMENTS:
          {
            cmtw.do_save_requirements ();
          }
          break;
        case IDM_EDITPATHS:
          {
            ListEditor editor (cmtw._path_list);
                
            editor.run (cmtw._instance, dialog);
          }
          break;
        case IDM_OUTPUT:
          break;
        }
      break;
    case WM_ACTIVATE:
      menu_item = LOWORD (parameter1);
          
      break;
    default:
      return (FALSE);
    }
  return (TRUE);
}
//---------------------------------------------------------------------

