//------------------------------------------------------------------------------
// emConfigModel.h
//
// Copyright (C) 2006-2008,2010 Oliver Hamann.
//
// Homepage: http://eaglemode.sourceforge.net/
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License version 3 as published by the
// Free Software Foundation.
//
// This program 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 General Public License version 3 for
// more details.
//
// You should have received a copy of the GNU General Public License version 3
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//------------------------------------------------------------------------------

#ifndef emConfigModel_h
#define emConfigModel_h

#ifndef emRec_h
#include <emCore/emRec.h>
#endif

#ifndef emModel_h
#include <emCore/emModel.h>
#endif


//==============================================================================
//=============================== emConfigModel ================================
//==============================================================================

class emConfigModel : public emModel {

public:

	// Base class for a configuration model where the data is stored in an
	// emRec. This class is a little bit similar to emRecFileModel, but it
	// is not an emFileModel. The idea here is to have a loaded state
	// always.

	const emString & GetInstallPath() const;
		// Get the installation path/name of the configuration file.

	bool IsUnsaved() const;
		// Ask whether the record data is currently not saved to the
		// file.

	const emSignal & GetChangeSignal() const;
		// Signaled on every modification of the record and even on
		// change of IsUnsaved.

	void TrySave() throw(emString);
	void Save();
		// Save the record to the install path. On error, the first
		// version throws the error message, and the second version
		// calls emFatalError.

	//??? An auto-save mechanism should be implemented, so that saving is
	//??? performed automatically after each change, best with a small time
	//??? delay (a second or so). Maybe that auto-save mechanism should be
	//??? enabled by default.

protected:

	emConfigModel(emContext & context, const emString & name);
		// Do not forget to call PostConstruct from an overloaded
		// constructor.

	void PostConstruct(emRec & rec, const emString & installPath);
		// Must be called by the constructor of the derived class after
		// the record has been constructed.
		// Arguments:
		//   rec         - The record making up the configuration.
		//   installPath - Path/name of the configuration file, usually
		//                 a result of calling the global function
		//                 emGetInstallPath.

	virtual ~emConfigModel();
		// Destructor.

	void TryLoad() throw(emString);
	void Load();
		// Load the record from the install path. On error, the first
		// version throws the error message, the second version calls
		// emFatalError. This is typically called by the constructor of
		// the derived class or by a TryAcquire function. Hint:
		// Derivatives of emFilePanel may easily report an error with
		// its SetCustomError method, this is better than calling
		// emFatalError.

	void TryLoadOrInstall(const char * insSrcPath=NULL) throw(emString);
	void LoadOrInstall(const char * insSrcPath=NULL);
		// Like above, but if the file does not yet exist, an
		// installation is performed: If insSrcPath is not NULL, that
		// file is copied to the install path and loaded. Otherwise the
		// record is set to its default state and saved to the install
		// path. Any non existing parent directories of the install path
		// are created automatically.

	emRec & GetRec();
		// Not valid before PostConstruct has been called.

private:

	class RecLink : public emRecListener {
	public:
		RecLink(emConfigModel & model);
	protected:
		virtual void OnRecChanged();
	private:
		emConfigModel & Model;
	};
	friend class RecLink;

	emSignal ChangeSignal;
	RecLink Link;
	emString InstallPath;
	bool Unsaved;
};

inline const emString & emConfigModel::GetInstallPath() const
{
	return InstallPath;
}

inline bool emConfigModel::IsUnsaved() const
{
	return Unsaved;
}

inline const emSignal & emConfigModel::GetChangeSignal() const
{
	return ChangeSignal;
}

inline emRec & emConfigModel::GetRec()
{
	return *Link.GetListenedRec();
}


#endif
