Source: core/kekule.electrons.js

/**
 * @fileoverview
 * This file contains basic classes related with electrons (bond, lone pair...).
 * @author Partridge Jiang
 */

/*
 * requires /lan/classes.js
 * requires /core/kekule.common.js
 * requires /utils/kekule.utils.js
 */

/**
 * Represent an abstract electron set (bond, lone pair, etc.).
 * @class
 * @augments Kekule.ChemObject
 * @param {Float} electronCount Count of electrons in this set.
 *   Note that there may be partial electron in set, so a float value is used here.
 *
 * @property {Float} electronCount Count of electrons in this set.
 *   Note that there may be partial electron in set, so a float value is used here.
 */
Kekule.ElectronSet = Class.create(Kekule.ChemObject,
/** @lends Kekule.ElectronSet# */
{
	/** @private */
	CLASS_NAME: 'Kekule.ElectronSet',
	/**
	 * @constructs
	 */
	initialize: function($super, electronCount)
	{
		$super();
		this.setElectronCount(electronCount || Kekule.ElectronSet.UNSET_ELECTRONCOUNT);
	},
	/** @private */
	initProperties: function()
	{
		this.defineProp('electronCount', {'dataType': DataType.FLOAT});
	}
});
/**
 * Indicate the electron count is uncertain.
 * @constant
 */
Kekule.ElectronSet.UNSET_ELECTRONCOUNT = null;

/**
 * Represent unbonded form of electron sets.
 * @class
 * @augments Kekule.ElectronSet
 * @param {Float} electronCount Count of electrons in this set. If this param is not set,
 *   electron count will be regarded as bondOrder * 2.
 */
Kekule.UnbondedElectronSet = Class.create(Kekule.ElectronSet,
/** @lends Kekule.UnbondedElectronSet# */
{
	/** @private */
	CLASS_NAME: 'Kekule.UnBondedElectronSet',
	/**
	 * @constructs
	 */
	initialize: function($super, electronCount)
	{
		$super(electronCount);
	},
	/** @private */
	initProperties: function()
	{
	}
});

/**
 * Enumeration of bond types
 * @class
 */
Kekule.BondType = {
	/** Covalent bond, the default bond type */
	COVALENT: 'covalent',
	/** Ionic bond */
	IONIC: 'ionic',
	/** Coordinate bond */
	COORDINATE: 'coordinate',
	/** Metallic bond' */
	METALLIC: 'metallic',
	/** HYDROGEN bond */
	HYDROGEN: 'hydrogen',
	/** Unknown */
	UNKNOWN: null,
	/** Default type is covalent bond */
	DEFAULT: 'covalent'
};

/**
 * Enumeration of bond orders
 * @class
 */
Kekule.BondOrder = {
	/** Single bond */
	SINGLE: 1,
	/** Double bond. */
	DOUBLE: 2,
	/** Triple bond. */
	TRIPLE: 3,
	/** Quadruple bond. */
	QUAD: 4,
	/** Explicit Aromatic bond. */
	EXPLICIT_AROMATIC: 10,
	/** Other form of bond. */
	OTHER: 20,
	/** Uncertain bond. */
	UNSET: null,
	/** Default is a single bond */
	DEFAULT: 1,

	/**
	 * Get min valence of an atom to connect to a bond.
	 * @param {Object} bondOrder
	 * @returns {Float} Aromatic bond will return 1.5, means it is between single and double bond.
	 */
	getBondValence: function(bondOrder)
	{
		if (bondOrder === Kekule.BondOrder.UNSET)
			return 0;
		else if (bondOrder == Kekule.BondOrder.EXPLICIT_AROMATIC)
			return 1.5;
		else
			return bondOrder;
	}
};

/**
 * Represent a typical bond form of molecule.
 * @class
 * @augments Kekule.ElectronSet
 * @param {Int} bondOrder Order of bond. Usually electronCount / 2.
 * @param {Float} electronCount Count of electrons in this set. If this param is not set,
 *   electron count will be regarded as bondOrder * 2.
 * @param {String} bondType Type of bond, a value from {@link Kekule.BondType}.
 *   If not specified, the bond will be regarded as a covalent one.
 *
 * @property {String} bondType Type of bond, a value from {@link Kekule.BondType}.
 * @property {Num} bondOrder Order of bond. Values should be retrieved from {@link Kekule.BondOrder}.
 * @property {Num} bondValence Valence comsumed of an atom to connect to this bond. Note this value is different from {@link Kekule.BondForm#bondOrder},
 *   For example, bondOrder value for {@link Kekule.BondOrder.EXPLICIT_AROMATIC} is 10, but the valence is 1.5. This property is read only.
 */
Kekule.BondForm = Class.create(Kekule.ElectronSet,
/** @lends Kekule.BondForm# */
{
	/** @private */
	CLASS_NAME: 'Kekule.BondForm',
	/**
	 * @constructs
	 */
	initialize: function($super, bondOrder, electronCount, bondType)
	{
		$super(electronCount);
		this.setBondOrder(bondOrder || Kekule.BondOrder.DEFAULT);
		if (Kekule.ObjUtils.notUnset(bondType))
			this.setBondType(bondType);
		if (Kekule.ObjUtils.notUnset(electronCount))
			this.setElectronCount(electronCount);
	},
	/** @private */
	initProperties: function()
	{
		this.defineProp('bondType', {
			'dataType': DataType.STRING,
			'enumSource': Kekule.BondType,
			'getter': function() { var r = this.getPropStoreFieldValue('bondType'); return (r? r: Kekule.BondType.DEFAULT); }
		});
		this.defineProp('bondOrder', {
			'dataType': DataType.FLOAT,
			'enumSource': Kekule.BondOrder,
			'setter': function(value)
				{
					if (this.getPropStoreFieldValue('bondOrder') != value)
					{
						this.setPropStoreFieldValue('bondOrder', value);
						if (value)
						{
							if (this.getBondType() == Kekule.BondType.COVALENT)
							{
								this.setElectronCount(this.getBondValence() * 2);
							}
						}
						else if (value === Kekule.BondOrder.UNSET)
							this.setElectronCount(Kekule.ElectronSet.UNSET_ELECTRONCOUNT);
					}
				}
		});
		this.defineProp('electronCount', {
			'dataType': DataType.FLOAT
		});
		this.defineProp('bondValence', {
			'dataType': DataType.FLOAT,
			'serializable': false,
			'getter': function() { return Kekule.BondOrder.getBondValence(this.getBondOrder()); },
			'setter': null
		});
	}
});

/*
 * Indicate the bond order is uncertain.
 * @constant
 */
//Kekule.BondForm.UNSET_BONDORDER = null;

//======================================================
/**
 * Factory to create and get suitable bond form objects.
 * @class
 */
Kekule.BondFormFactory = {
	/** @private */
	_bondForms: {},
	/** @private */
	getBondFormId: function(bondOrder, electronCount, bondType)
	{
		var result = '';
		if (bondType)
			result += bondType + '_';
		if (bondOrder)
			result += Number(bondOrder).toString();
		if (electronCount)
			result += '_' + Number(electronCount).toString();
		return result;
	},
	/**
	 * Returns a suitable {@link Kekule.BondForm} object.
	 * @param {Int} bondOrder Order of bond.
	 * @param {Float} electronCount Number of electrons. Usually you can bypass this param.
	 * @param {String} bondType Type of bond.
	 * @returns {Kekule.BondForm}
	 */
	getBondForm: function(bondOrder, electronCount, bondType)
	{
		if ((!bondOrder) && (!electronCount) && (!bondType))
			return undefined;
		if (!bondType)
			bondType = Kekule.BondType.DEFAULT;
		if ((!electronCount) && (bondOrder) && (bondType === Kekule.BondType.COVALENT))
		{
			var bondValence = Kekule.BondOrder.getBondValence(bondOrder);
			electronCount = bondValence * 2;
		}
		var id = Kekule.BondFormFactory.getBondFormId(bondOrder, electronCount, bondType);
		if (!Kekule.BondFormFactory._bondForms[id])
			Kekule.BondFormFactory._bondForms[id] = new Kekule.BondForm(bondOrder, electronCount, bondType);
		return Kekule.BondFormFactory._bondForms[id];
	}
};

/**
 * Enumeration of radical types
 * @class
 */
Kekule.RadicalOrder = {
	NONE: 0,
	SINGLET: 1,
	DOUBLET: 2,
	TRIPLET: 3,
	DEFAULT: 0,

	/**
	 * Returns the electron number of this radical.
	 * @param {Int} radicalOrder Value from {@link Kekule.RadicalOrder}.
	 * @returns {Int}
	 */
	getRadicalElectronCount: function(radicalOrder)
	{
		var O = Kekule.RadicalOrder;
		if (Kekule.ObjUtils.isUnset(radicalOrder) || (radicalOrder === O.NONE))
			return 0;
		else if (radicalOrder === O.DOUBLET)
			return 1;
		else
			return 2;
	}
};

/**
 * Enumeration of hybridization types
 * @class
 */
Kekule.HybridizationType = {
	/** hybridization type is not determined. **/
	UNKNOWN: null,
	/** sp. **/
	SP: 1,
	/** sp2 **/
	SP2: 2,
	/** sp3 **/
	SP3: 3,
	/** Explicitly no hybridization. */
	NONE: 0
};