/**
* @fileoverview
* Reader and Writer classes for MDL V2000 and V3000 formats.
* @author Partridge Jiang
*/
/*
* requires /lan/classes.js
* requires /core/kekule.common.js
* requires /core/kekule.elements.js
* requires /core/kekule.electrons.js
* requires /core/kekule.structures.js
* requires /core/kekule.reactions.js
* requires /utils/kekule.textHelper.js
* requires /io/kekule.io.js
* requires /io/mdl/kekule.io.mdlBase.js
* requires /io/mdl/kekule.io.mdl2000.js
* requires /io/mdl/kekule.io.mdl3000.js
* requires /localization
*/
/*
* Default options to read/write CML format data.
* @object
*/
Kekule.globalOptions.add('IO.mdl', {
mdlVersion: Kekule.IO.MdlVersion.V2000,
coordMode: Kekule.CoordMode.UNKNOWN
});
/**
* Class to read and anaylsis MDL 2000 / 3000 Connection Table block.
* @class
* @augments Kekule.IO.MdlBlockReader
* @private
*/
Kekule.IO.MdlStructureFragmentReader = Class.create(Kekule.IO.MdlBlockReader,
/** @lends Kekule.IO.MdlStructureFragmentReader# */
{
/** @private */
CLASS_NAME: 'Kekule.IO.MdlStructureFragmentReader',
/** @constructs */
initialize: function($super, coordMode)
{
$super();
this.setCoordMode(coordMode || Kekule.CoordMode.UNKNOWN);
},
/** @private */
initProperties: function()
{
this.defineProp('coordMode', {'dataType': DataType.INT, 'defaultValue': Kekule.CoordMode.UNKNOWN});
},
/** @private */
createFragment: function(parentObj)
{
// descendants should override this.
},
/** @private */
createCtabReader: function(mdlVersion)
{
if (mdlVersion == Kekule.IO.MdlVersion.V3000)
return new Kekule.IO.Mdl3kCTabReader();
else
return new Kekule.IO.Mdl2kCTabReader();
},
/** @private */
getCtabVersion: function(textBuffer)
{
var pos = textBuffer.getCurrLineNo();
var line = textBuffer.readLine();
textBuffer.setCurrLineNo(pos);
// check version tag at the end of line
var s = line.substr(33, 6).trim();
if (s == 'V3000')
return Kekule.IO.MdlVersion.V3000;
else if (s == 'V2000')
return Kekule.IO.MdlVersion.V2000;
else // wrong version flag, it may be a CTAB 2000
{
//Kekule.error(Kekule.ErrorMsg.NOT_MDL_FORMAT_DATA);
//return null;
return Kekule.IO.MdlVersion.V2000;
}
},
/**
* Create CTab of fragment by ctabInfo JSON data.
* @param {Kekule.StructureFragment} fragment
* @param {Hash} ctabInfo
* @returns {Kekule.StructureConnectionTable}
* @private
*/
createStructureFromJson: function(ctabInfo, parentObj)
{
var fragment = this.createFragment();
if (fragment)
Kekule.IO.MdlStructureUtils.fillFragment(fragment, ctabInfo, this.getCoordMode());
return fragment;
},
/** @private */
doReadBlock: function($super, textBuffer, parentObj)
{
// check ctab format, V2000 or V3000
var version = this.getCtabVersion(textBuffer);
if (!version)
return null;
/*
var buffer = (version == Kekule.IO.MdlVersion.V2000)? textBuffer:
new Kekule.IO.Mdl3kTextBuffer(textBuffer.getLines()); // V3000 need different type of text buffer
*/
var ctabReader = this.createCtabReader(version);
/*
if (version == Kekule.IO.MdlVersion.V3000)
var ctabInfo = ctabReader.readBlock(textBuffer.getText(), parentObj);
else
var ctabInfo = ctabReader.doReadBlock(buffer, parentObj);
*/
//var ctabInfo = ctabReader.readBlock(textBuffer.getUnreadLines(), parentObj);
var ctabInfo = ctabReader.doReadBlock(textBuffer, parentObj);
if (ctabInfo.atomInfos.coordMode)
this._forceCoordMode = ctabInfo.atomInfos.coordMode;
var result = this.createStructureFromJson(ctabInfo, parentObj);
return result;
}
});
/**
* Class to write a {@link Kekule.StructureFragment} to MDL 2000 / 3000 Connection Table block.
* @class
* @augments Kekule.IO.MdlBlockWriter
* @private
*/
Kekule.IO.MdlStructureFragmentWriter = Class.create(Kekule.IO.MdlBlockWriter,
/** @lends Kekule.IO.MdlStructureFragmentWriter# */
{
/** @private */
CLASS_NAME: 'Kekule.IO.MdlStructureFragmentWriter',
/** @constructs */
initialize: function($super, version, coordMode)
{
$super();
this.setMdlVersion(version || Kekule.IO.MdlVersion.V2000);
this.setCoordMode(coordMode || Kekule.CoordMode.UNKNOWN);
},
/** @private */
initProperties: function()
{
this.defineProp('mdlVersion', {'dataType': DataType.INT, 'defaultValue': Kekule.IO.MdlVersion.V2000});
this.defineProp('coordMode', {'dataType': DataType.INT, 'defaultValue': Kekule.CoordMode.UNKNOWN});
},
/** @private */
createCtabWriter: function(mdlVersion)
{
if (mdlVersion == Kekule.IO.MdlVersion.V3000)
return new Kekule.IO.Mdl3kCTabWriter(this.getCoordMode());
else
return new Kekule.IO.Mdl2kCTabWriter(this.getCoordMode());
},
/** @private */
doWriteBlock: function($super, obj, textBuffer)
{
var ctabWriter = this.createCtabWriter(this.getMdlVersion());
var text = ctabWriter.writeBlock(obj);
textBuffer.writeText(text);
}
});
/**
* Directly read CTab block of MDL 3000 MOL file.
* First 4 lines of MDL 3000 MOL file are for backward compatibility and has little use.
* So this reader skips them and read CTAB block directly.
* @class
* @augments Kekule.IO.MdlStructureFragmentReader
* @private
*/
Kekule.IO.Mdl3kMoleculeCTabReader = Class.create(Kekule.IO.MdlStructureFragmentReader,
/** @lends Kekule.IO.Mdl3kMoleculeCTabReader# */
{
/** @private */
CLASS_NAME: 'Kekule.IO.Mdl3kMoleculeCTabReader',
/** @private */
createFragment: function(parentObj)
{
return new Kekule.Molecule();
},
/** @private */
doReadBlock: function($super, textBuffer, parentObj)
{
var ctabReader = this.createCtabReader(Kekule.IO.MdlVersion.V3000);
//var ctabInfo = ctabReader.readBlock(textBuffer.getUnreadLines(), parentObj);
var ctabInfo = ctabReader.doReadBlock(textBuffer, parentObj);
return this.createStructureFromJson(ctabInfo, parentObj);
}
});
/**
* Directly write CTab block of MDL 3000 MOL file.
* First 4 lines of MDL 3000 MOL file are for backward compatibility and has little use.
* So this writer skips them and write CTAB block directly.
* @class
* @augments Kekule.IO.MdlStructureFragmentWriter
* @private
*/
Kekule.IO.Mdl3kMoleculeCTabWriter = Class.create(Kekule.IO.MdlStructureFragmentWriter,
/** @lends Kekule.IO.Mdl3kMoleculeCTabWriter# */
{
/** @private */
CLASS_NAME: 'Kekule.IO.Mdl3kMoleculeCTabWriter',
/** @constructs */
initialize: function($super, coordMode)
{
$super(Kekule.IO.MdlVersion.V3000, coordMode);
},
/** @private */
doWriteBlock: function($super, obj, textBuffer)
{
var ctabWriter = new Kekule.IO.Mdl3kCTabWriter(this.getCoordMode());;
var text = ctabWriter.writeBlock(obj);
textBuffer.writeText(text);
}
});
/**
* Class to read and anaylsis MDL MOL 2000/3000 data and create Molecule.
* @class
* @augments Kekule.IO.MdlStructureFragmentReader
*/
Kekule.IO.MdlMoleculeReader = Class.create(Kekule.IO.MdlStructureFragmentReader,
/** @lends Kekule.IO.MdlMoleculeReader# */
{
/** @private */
CLASS_NAME: 'Kekule.IO.MdlMoleculeReader',
/** @private */
createFragment: function(parentObj)
{
var result = new Kekule.Molecule();
return result;
},
/**
* Read MOL 2000/3000 file header lines.
* @param {Kekule.TextLinesBuffer} textBuffer
* @param {Object} parentObj
* @return {Hash}
* @private
*/
readHeaderInfo: function(textBuffer, parentObj)
{
var result = {};
// line 1: molecule name
var name = textBuffer.readLine();
if (name)
result.name = name;
// line 2: MOL file information
var infoLine = textBuffer.readLine();
var info = this.readInfoLine(infoLine);
if (info)
result = Object.extend(result, info);
// line 3: comment
var comment = textBuffer.readLine();
if (comment)
result.comment = comment;
return result;
},
/**
* Read information line (line 2) of a MOL 2000 / 3000 file.
* @param {String} line
* @returns {Hash}
* @private
*/
readInfoLine: function(line)
{
var result = {};
if (line.trim()) // info line can be blank
{
// IIPPPPPPPPMMDDYYHHmmddSSssssssssssEEEEEEEEEEEERRRRRR
// II: User's first and last initials
var s = line.substr(0, 2).trim();
if (s)
result.userAbbr = s;
// PPPPPPPP: program name
s = line.substr(2, 8).trim();
if (s)
result.programName = s;
// MMDDYYHHmm: Date and time
//var date;
s = line.substr(10, 10);
if (s.trim())
{
/*
date = new Date();
var month = (parseInt(line.substr(10, 2).trim()) || 1) - 1;
var day = parseInt(line.substr(12, 2).trim()) || 0;
var year = parseInt(line.substr(14, 2), 10) || 0;
if (year >= 70) // assume 1970-1999
year += 1900;
else // 2000-2069
year += 2000
date.setFullYear(year, month, day);
var hour = parseInt(line.substr(16, 2), 10) || 0;
var minute = parseInt(line.substr(18, 2), 10) || 0;
date.setHours(hour, minute);
result.date = date;
*/
result.date = Kekule.IO.MdlUtils.analysisMdlDateTimeStr(s, false);
}
// dd: dimensional codes, 2D or 3D
s = line.substr(20, 2);
result.coordMode = (s == '3D')?
Kekule.CoordMode.COORD3D:
((s == '2D')? Kekule.CoordMode.COORD2D: Kekule.CoordMode.UNKNOWN );
// SSssssssssss: scaling factors
// TODO: not parsed here, may be this property is important.
// EEEEEEEEEEEE: energy, no need to parse
// RRRRRR: registry info, no need to parse
}
return result;
},
/** @private */
doReadBlock: function($super, textBuffer, parentObj)
{
var headerInfo = this.readHeaderInfo(textBuffer, parentObj);
if (headerInfo && (typeof(headerInfo.coordMode) != 'undefined'))
this.setCoordMode(headerInfo.coordMode);
var mol = $super(textBuffer, parentObj);
// add header information to mol
if (mol && headerInfo)
{
headerInfo.name? mol.setName(headerInfo.name): null;
headerInfo.userAbbr? mol.setInfoValue('author', headerInfo.userAbbr): null;
headerInfo.programName? mol.setInfoValue('generator', headerInfo.programName): null;
headerInfo.date? mol.setInfoValue('date', headerInfo.date): null;
headerInfo.comment? mol.setInfoValue('comment', headerInfo.comment): null;
}
// check if next line is M END
// in 3k, this line will not be read by ctab reader, so just read and discard it
if (!textBuffer.eof())
{
var line = textBuffer.getCurrLine();
if (line.trim().toUpperCase() === 'M END')
textBuffer.readLine();
}
return mol;
}
});
/**
* Class to write {@link Kekule.Molecule} to MDL MOL 2000/3000 data.
* @class
* @augments Kekule.IO.MdlStructureFragmentWriter
*/
Kekule.IO.MdlMoleculeWriter = Class.create(Kekule.IO.MdlStructureFragmentWriter,
/** @lends Kekule.IO.MdlMoleculeWriter# */
{
/** @private */
CLASS_NAME: 'Kekule.IO.MdlMoleculeWriter',
/**
* Write MOL 2000/3000 file header lines.
* @param {Kekule.Molecule} mol
* @param {Kekule.TextLinesBuffer} textBuffer
* @private
*/
writeHeaderInfo: function(mol, textBuffer)
{
// line 1: molecule name
textBuffer.writeLine(mol.getName() || /*Kekule.Texts.UNNAMED*/Kekule.$L('Texts.UNNAMED') || '');
// line 2: MOL file information
var infoLine = this.generateInfoLine(mol);
textBuffer.writeLine(infoLine);
// line 3: comment
var comment = mol.getInfoValue('comment');
textBuffer.writeLine(comment || '');
},
/**
* Get information line (line 2) for writing to MOL 2000 / 3000 file.
* @param {Kekule.Molecule} mol
* @returns {String}
* @private
*/
generateInfoLine: function(mol)
{
var s = '';
// IIPPPPPPPPMMDDYYHHmmddSSssssssssssEEEEEEEEEEEERRRRRR
// II: User's first and last initials
var author = mol.getInfoValue('author');
s += author? author.toString().substr(0, 2).rpad(2): ' ';
// PPPPPPPP: program name
var progName = mol.getInfoValue('generator');
s += progName? progName.toString().substr(0, 8).rpad(8): Kekule.LIBNAME_CORE.rpad(8);
// MMDDYYHHmm: Date and time
var date = mol.getInfoValue('date') || new Date(); // default is now
s += Kekule.IO.MdlUtils.generateMdlDateTimeStr(date, false); // short date time format
// dd: dimensional codes, 2D or 3D
s += (this.getCoordMode() == Kekule.CoordMode.COORD3D)? '3D': '2D';
// SSssssssssss: scaling factors
// TODO: not handled here, may be this property is important.
// EEEEEEEEEEEE: energy, no need to handle
// RRRRRR: registry info, no need to handle
return s;
},
/**
* Get molecule data from an object.
* @param {Variant} obj
*/
getMolecule: function(obj)
{
return Kekule.ChemStructureUtils.getTotalStructFragment(obj);
},
/** @private */
doWriteBlock: function($super, obj, textBuffer)
{
var mol = this.getMolecule(obj);
if (mol)
{
var molInfo = Kekule.IO.MdlStructureUtils.getMoleculeCtabStructureInfo(mol);
this.setCoordMode(molInfo.coordMode); // coord mode can be get from mol info
// header
this.writeHeaderInfo(mol, textBuffer);
if (this.getMdlVersion() == Kekule.IO.MdlVersion.V3000) // add a compatible count line
textBuffer.writeLine(Kekule.IO.MdlStructureUtils.generateClassicStyleCountLine(molInfo, this.getMdlVersion()));
// Ctab
$super(mol, textBuffer);
if (this.getMdlVersion() == Kekule.IO.MdlVersion.V3000) // 3k compatible end tag
textBuffer.writeLine('M END');
}
else // not found
{
// do nothing
}
}
});
/**
* Class to read and anaylsis both MDL SD file data then create Molecule or MoleculeList.
* @class
* @augments Kekule.IO.MdlBlockReader
* @private
*/
Kekule.IO.MdlStructDataReader = Class.create(Kekule.IO.MdlBlockReader,
/** @lends Kekule.IO.MdlStructDataReader# */
{
/** @private */
CLASS_NAME: 'Kekule.IO.MdlStructDataReader',
/** @private */
DATA_HEAD_PREFIX: Kekule.IO.MDL.SD_DATA_HEAD_PREFIX, //'>',
/** @private */
DATA_DBFIELD_PATTERN: /\bDT(\d+)\b/,
/** @private */
DATA_KEY_NAME_PATTERN: /\<(.+)\>/,
/** @private */
MOL_DELIMITER: Kekule.IO.MDL.MOL_DELIMITER, //'$$$$',
/** @private */
doReadBlock: function(textBuffer, parentObj)
{
var molReader = new Kekule.IO.MdlMoleculeReader();
try
{
var currKey, currValue;
var mol;
var mols = [];
// repeatly, read mol block than data block
while (!textBuffer.eof())
{
try
{
mol = molReader.doReadBlock(textBuffer, null);
}
catch(e) // tailing blank lines after $$$$ may cause error in reading mol, just ignore it and terminate reading
{
mol = null;
}
if (mol) // read data block
{
mols.push(mol);
currKey = null;
currValue = null;
while (!textBuffer.eof())
{
var lineInfo = this.analysisDataLine(textBuffer.readLine());
if (lineInfo)
{
var lineType = lineInfo.lineType;
if (lineType === 'dataheader')
currKey = lineInfo.key;
else if (lineType === 'datavalue')
{
if (currKey)
{
currValue = lineInfo.value;
mol.setInfoValue(currKey, currValue);
}
}
else if (lineType === 'moldelimiter')
break; // exit data read loop to read the next molecule
}
}
}
else
break;
}
if (mols.length > 1) // more than one molecule, returns a list
{
var result = new Kekule.ChemObjList();
for (var i = 0, l = mols.length; i < l; ++i)
result.append(mols[i]);
return result;
}
else
return mols[0];
}
finally
{
molReader.finalize();
}
},
/** @private */
analysisDataLine: function(line)
{
var lineType, key, value;
var s = line.trim();
if (s.startsWith(this.DATA_HEAD_PREFIX)) // data header, read data key name
{
lineType = 'dataheader';
key = this.getDataHeaderKey(line);
if (key)
return {'lineType': lineType, 'key': key};
else
return null;
}
else if (s.startsWith(this.MOL_DELIMITER)) // molecule delimiter
{
return {'lineType': 'moldelimiter'};
}
else // data line or blank line
{
if (!s) // blank
return null;
else
return {'lineType': 'datavalue', 'value': line};
}
},
/** @private */
getDataHeaderKey: function(line)
{
var key = null;
// try get key name
var result = this.DATA_KEY_NAME_PATTERN.exec(line);
if (result && (result.length > 1))
key = result[1];
else // try get database field name
{
result = this.DATA_DBFIELD_PATTERN.exec(line);
if (result && (result.length > 1))
key = result[1];
else // do not know the exactly key, return whole line
key = line;
}
return key;
},
doReadDataBlock: function(textBuffer, mol)
{
var line = textBuffer.readLine();
// if start with '>', is a data header
}
});
/**
* Class to write {@link Kekule.Molecule} or other molecule list to MDL SD format data.
* @class
* @augments Kekule.IO.MdlStructureFragmentWriter
*/
Kekule.IO.MdlStructDataWriter = Class.create(Kekule.IO.MdlBlockWriter,
/** @lends Kekule.IO.MdlStructDataWriter# */
{
/** @private */
CLASS_NAME: 'Kekule.IO.MdlStructDataWriter',
/** @private */
IGNORED_INFO_FIELDS: ['generator', 'author', 'date', 'comment'],
/** @constructs */
initialize: function($super, version, coordMode)
{
$super();
this.setMdlVersion(version || Kekule.IO.MdlVersion.V2000);
this.setCoordMode(coordMode || Kekule.CoordMode.UNKNOWN);
},
/** @private */
initProperties: function()
{
this.defineProp('mdlVersion', {'dataType': DataType.INT, 'defaultValue': Kekule.IO.MdlVersion.V2000});
this.defineProp('coordMode', {'dataType': DataType.INT, 'defaultValue': Kekule.CoordMode.UNKNOWN});
},
/** @private */
doWriteBlock: function(chemObj, textBuffer)
{
var mols = this.getChildMols(chemObj);
var molWriter = new Kekule.IO.MdlMoleculeWriter();
molWriter.setMdlVersion(this.getMdlVersion());
molWriter.setCoordMode(this.getCoordMode());
for (var i = 0, l = mols.length; i < l; ++i)
{
var mol = mols[i];
// write molecule
try
{
var text = molWriter.writeBlock(mol);
textBuffer.writeText(text);
// write data information
var data = this.getMolData(mol);
this.doWriteDataBlock(data, textBuffer);
// then molecule delimiter
textBuffer.writeLine(Kekule.IO.MDL.MOL_DELIMITER);
}
catch(e)
{
// emit the error when meet a formula molecule
}
}
},
/** @private */
doWriteDataBlock: function(data, textBuffer)
{
var keys = Kekule.ObjUtils.getOwnedFieldNames(data);
for (var i = 0, l = keys.length; i < l; ++i)
{
var key = keys[i];
if (this.IGNORED_INFO_FIELDS.indexOf(key) < 0)
{
var header = Kekule.IO.MDL.SD_DATA_HEAD_PREFIX + ' <' + key + '>';
var value = data[key];
// write data/value and a blank line
if (header && value)
{
textBuffer.writeLine(header);
textBuffer.writeLine(value);
textBuffer.writeLine('');
}
}
}
},
/**
* Returns child molecule in parent chemObj.
* Each child molecule need a block in MDL SD file.
* @param {Kekule.ChemObject} chemObj
* @returns {Array}
*/
getChildMols: function(chemObj)
{
var children = Kekule.ChemStructureUtils.getChildStructureObjs(chemObj, true);
/*
if (chemObj instanceof Kekule.ChemObjList)
children = chemObj.getItems();
else if (chemObj instanceof Kekule.CompositeMolecule)
children = chemObj.getSubMolecules().getAllObjs();
else if (chemObj instanceof Kekule.ChemStructureObjectGroup)
children = chemObj.getAllObjs();
else // single object
children = [chemObj];
*/
// filter out molecule
var result = [];
for (var i = 0, l = children.length; i < l; ++i)
{
var child = children[i];
if (child instanceof Kekule.StructureFragment)
result.push(child);
}
return result;
},
/**
* Returns a hash with all data need to write to SD content.
* @param {Kekule.ChemObject} mol
* @returns {Hash}
*/
getMolData: function(mol)
{
var info = mol.getInfo? mol.getInfo() || {}: null;
return info;
}
});
/**
* Base class to read and anaylsis both MDL RXN 2000 and 3000 data then create Reaction.
* @class
* @augments Kekule.IO.MdlBlockReader
* @private
*/
Kekule.IO.MdlBaseReactionReader = Class.create(Kekule.IO.MdlBlockReader,
/** @lends Kekule.IO.MdlBaseReactionReader# */
{
/** @private */
CLASS_NAME: 'Kekule.IO.MdlBaseReactionReader',
/**
* Read header block (first 4 lines) of a RXN file.
* @param {Kekule.TextLinesBuffer} textBuffer
* @param {Object} parentObj
* @returns {Hash}
* @private
*/
readHeaderBlock: function(textBuffer, parentObj)
{
var result = {};
var s;
// line 1: identifier
var line = textBuffer.readLine().trim();
s = line.substr(0, 4);
if (s != '$RXN') // identifier wrong
{
Kekule.error(/*Kekule.ErrorMsg.NOT_MDL_RXN_DATA*/Kekule.$L('ErrorMsg.NOT_MDL_RXN_DATA'));
return null;
}
else // get file version
{
s = line.substr(4).trim();
if (s == 'V3000')
result.version = Kekule.IO.MdlVersion.V3000;
else
result.version = Kekule.IO.MdlVersion.V2000;
}
// line 2: reaction name
line = textBuffer.readLine().trim();
if (line)
result.name = line;
// line 3: reaction info
// IIIIIIPPPPPPPPPMMDDYYYYHHmmRRRRRRR
{
line = textBuffer.readLine();
// IIIIII: User's initials
s = line.substr(0, 6).trim();
if (s)
result.userAbbr = s;
// PPPPPPPPP: program name
s = line.substr(6, 9).trim();
if (s)
result.programName = s;
// MMDDYYYYHHmm: date time.
// NOTE: early softwares may generate datetime string in short format, doesnot handle this now.
s = line.substr(15, 10);
if (s.trim())
result.date = Kekule.IO.MdlUtils.analysisMdlDateTimeStr(s, true);
// RRRRRRR: reg no, ignored
}
// line 4: comment line
line = textBuffer.readLine().trim();
if (line)
result.comment = line;
return result;
//return Kekule.IO.MdlUtils.parseReactionHeader(textBuffer);
},
/**
* Get reactant and product count from count line.
* @param {Object} line
* @private
*/
readSubstanceCountLine: function(line)
{
// do nothing here
},
/**
* Read MOL blocks in RXN file.
* @param {Kekule.TextLinesBuffer} textBuffer
* @returns {Kekule.Molecule}
* @private
*/
readMolBlock: function(textBuffer)
{
// do nothing here
},
/** @private */
doReadBlock: function($super, textBuffer, parentObj)
{
var headerInfo = this.readHeaderBlock(textBuffer, null);
// read header info success, this is a legal RXN file, do other jobs
var substanceInfo = this.readSubstanceCountLine(textBuffer.readLine());
var result = new Kekule.Reaction();
// then MOL blocks
var line = '';
/*
while (line != '$MOL')
line = textBuffer.readLine();
*/
for (var i = 0; i < substanceInfo.reactantCount; ++i)
{
var mol = this.readMolBlock(textBuffer);
if (mol)
result.appendReactant(mol);
}
for (var i = 0; i < substanceInfo.productCount; ++i)
{
var mol = this.readMolBlock(textBuffer);
if (mol)
result.appendProduct(mol);
}
// append meta info
if (result && headerInfo)
{
headerInfo.name? result.setName(headerInfo.name): null;
headerInfo.userAbbr? result.setInfoValue('author', headerInfo.userAbbr): null;
headerInfo.programName? result.setInfoValue('generator', headerInfo.programName): null;
headerInfo.date? result.setInfoValue('date', headerInfo.date): null;
headerInfo.comment? result.setInfoValue('comment', headerInfo.comment): null;
}
return result;
}
});
/**
* Class to read and anaylsis MDL RXN 2000 data and create Reaction.
* @class
* @augments Kekule.IO.MdlBaseReactionReader
* @private
*/
Kekule.IO.Mdl2kReactionReader = Class.create(Kekule.IO.MdlBaseReactionReader,
/** @lends Kekule.IO.Mdl2kReactionReader# */
{
/** @private */
CLASS_NAME: 'Kekule.IO.Mdl2kReactionReader',
/** @private */
readHeaderBlock: function($super, textBuffer, parentObj)
{
var result = $super(textBuffer, parentObj);
if (result.version != Kekule.IO.MdlVersion.V2000)
{
Kekule.error(/*Kekule.ErrorMsg.NOT_MDL2000_RXN_DATA*/Kekule.$L('ErrorMsg.NOT_MDL2000_RXN_DATA'));
return null;
}
else
return result;
},
/**
* Get reactant and product count from count line.
* @param {Object} line
* @private
*/
readSubstanceCountLine: function(line)
{
var result = {};
// rrrppp
result.reactantCount = parseInt(line.substr(0, 3), 10) || 0;
result.productCount = parseInt(line.substr(3, 3), 10) || 0;
return result;
},
/** @private */
readMolBlock: function(textBuffer)
{
var line = textBuffer.readLine(); //textBuffer.getLineAt(textBuffer.getCurrLineNo());
while ((line !== '$MOL') && (!textBuffer.eof()))
line = textBuffer.readLine(); // skip heading $MOL mark
if (textBuffer.eof()) // can not find mol block
return null;
// fetch lines until $MOL end tag if found
var lines = [];
//var line = textBuffer.readLine();
var line = textBuffer.getCurrLine();
while ((line !== '$MOL') && (!textBuffer.eof()))
{
lines.push(line);
textBuffer.incCurrLineNo();
//line = textBuffer.readLine();
line = textBuffer.getCurrLine();
}
return (new Kekule.IO.MdlMoleculeReader()).readBlock(lines, null);
}
});
/**
* Class to read and anaylsis MDL RXN 3000 data and create Reaction.
* @class
* @augments Kekule.IO.MdlBaseReactionReader
* @private
*/
Kekule.IO.Mdl3kReactionReader = Class.create(Kekule.IO.MdlBaseReactionReader,
/** @lends Kekule.IO.Mdl3kReactionReader# */
{
/** @private */
CLASS_NAME: 'Kekule.IO.Mdl3kReactionReader',
/** @private */
createTextBuffer: function()
{
return (new Kekule.IO.Mdl3kTextBuffer());
},
/** @private */
readHeaderBlock: function($super, textBuffer, parentObj)
{
var result = $super(textBuffer, parentObj);
if (result.version != Kekule.IO.MdlVersion.V3000)
{
Kekule.error(/*Kekule.ErrorMsg.NOT_MDL3000_RXN_DATA*/Kekule.$L('ErrorMsg.NOT_MDL3000_RXN_DATA'));
return null;
}
else
return result;
},
/** @private */
readSubstanceCountLine: function(line)
{
var result = {};
// M V30 COUNTS rcount pcount
var values = Kekule.IO.Mdl3kValueUtils.splitValues(line);
if (values.shift().value.trim() != 'COUNTS') // not a count line
{
Kekule.error(/*Kekule.ErrorMsg.NOT_MDL3000_RXN_COUNTLINE*/Kekule.$L('ErrorMsg.NOT_MDL3000_RXN_COUNTLINE'));
return null;
}
result.reactantCount = parseInt(values.shift().value, 10) || 0;
result.productCount = parseInt(values.shift().value, 10) || 0;
return result;
},
/** @private */
readMolBlock: function(textBuffer)
{
if (textBuffer.getBlockBuffer)
{
var buffer = textBuffer.getBlockBuffer('CTAB');
return (new Kekule.IO.Mdl3kMoleculeCTabReader()).doReadBlock(buffer);
}
else
return null;
}
});
/**
* Class to read and anaylsis both RXN 2000 and 3000 data then create Reaction.
* @class
* @augments Kekule.IO.MdlBlockReader
*/
Kekule.IO.MdlReactionReader = Class.create(Kekule.IO.MdlBlockReader,
/** @lends Kekule.IO.MdlReactionReader# */
{
/** @private */
CLASS_NAME: 'Kekule.IO.MdlReactionReader',
/** @private */
doReadBlock: function(textBuffer, parentObj)
{
var reader;
var version = Kekule.IO.MdlUtils.getRxnMarkVersion(textBuffer.getCurrLine());
if (version == Kekule.IO.MdlVersion.V3000)
reader = new Kekule.IO.Mdl3kReactionReader();
else
reader = new Kekule.IO.Mdl2kReactionReader();
return reader.readBlock(textBuffer.getUnreadLines(), parentObj);
}
});
/**
* Class to write both MDL RXN 2000 and 3000 data.
* @class
* @augments Kekule.IO.MdlBlockWriter
* @private
*/
Kekule.IO.MdlReactionWriter = Class.create(Kekule.IO.MdlBlockWriter,
/** @lends Kekule.IO.MdlReactionWriter# */
{
/** @private */
CLASS_NAME: 'Kekule.IO.MdlReactionWriter',
/** @constructs */
initialize: function($super, version, coordMode)
{
$super();
this.setMdlVersion(version || Kekule.IO.MdlVersion.V2000);
this.setCoordMode(coordMode || Kekule.CoordMode.UNKNOWN);
},
/** @private */
initProperties: function()
{
this.defineProp('mdlVersion', {'dataType': DataType.INT, 'defaultValue': Kekule.IO.MdlVersion.V2000});
this.defineProp('coordMode', {'dataType': DataType.INT, 'defaultValue': Kekule.CoordMode.UNKNOWN});
},
/**
* Write header block (first 4 lines) of a RXN file.
* @param {Kekule.Reaction} reaction
* @param {Kekule.TextLinesBuffer} textBuffer
* @private
*/
writeHeaderBlock: function(reaction, textBuffer)
{
var s;
// line 1: identifier
s = '$RXN' + ((this.getMdlVersion() == Kekule.IO.MdlVersion.V3000)? ' ' + Kekule.IO.MDL.VER3000: '');
textBuffer.writeLine(s);
// line 2: reaction name
textBuffer.writeLine(reaction.getName() || '');
// line 3: reaction info
// IIIIIIPPPPPPPPPMMDDYYYYHHmmRRRRRRR
{
// IIIIII: User's initials
var author = reaction.getInfoValue('author') || '';
s = author.substr(0, 6).rpad(6);
// PPPPPPPPP: program name
var generator = reaction.getInfoValue('generator') || '';
s += generator.substr(0, 9).rpad(9);
// MMDDYYYYHHmm: date time.
var date = reaction.getInfoValue('date') || new Date(); // default is now
// NOTE: early softwares may generate datetime string in short format, doesnot handle this now.
s += Kekule.IO.MdlUtils.generateMdlDateTimeStr(date, true);
// RRRRRRR: reg no, ignored
}
textBuffer.writeLine(s);
// line 4: comment line
var comment = reaction.getInfoValue('comment') || '';
textBuffer.writeLine(comment);
},
/**
* Get reactant and product count line.
* @param {Kekule.Reaction} reaction
* @private
*/
generateSubstanceCountLine: function(reaction)
{
// 3k: M V30 COUNTS rcount pcount
if (this.getMdlVersion() == Kekule.IO.MdlVersion.V3000)
return 'M V30 COUNTS ' + Kekule.IO.Mdl3kValueUtils.mergeValues([reaction.getReactantCount(), reaction.getProductCount()]);
// 2k: rrrppp
return reaction.getReactantCount().toString().lpad(3) + reaction.getProductCount().toString().lpad(3);
},
/**
* Write delimiter between molecules.
* 2k will write '$MOL', 3k should do nothing
* @param {Object} textBuffer
*/
writeMolDelimiterLine: function(textBuffer)
{
if (this.getMdlVersion() == Kekule.IO.MdlVersion.V2000)
textBuffer.writeLine('$MOL');
},
/**
* Write MOL blocks in RXN file.
* @param {Kekule.Molecule} mol
* @param {Kekule.TextLinesBuffer} textBuffer
* @private
*/
writeMolBlock: function(mol, textBuffer)
{
var writer = this.getMdlVersion() == Kekule.IO.MdlVersion.V3000?
new Kekule.IO.Mdl3kMoleculeCTabWriter(this.getCoordMode()): // no need to write compatible lines in 3k
new Kekule.IO.MdlMoleculeWriter(this.getMdlVersion(), this.getCoordMode());
var text = writer.writeBlock(mol);
textBuffer.writeText(text);
},
/** @private */
doWriteBlock: function($super, reaction, textBuffer)
{
var is3kMode = this.getMdlVersion() == Kekule.IO.MdlVersion.V3000;
// if in 3k mode, reactant and products should be surrounded by block begin/end tag
// header
this.writeHeaderBlock(reaction, textBuffer);
var substanceInfoLine = this.generateSubstanceCountLine(reaction);
textBuffer.writeLine(substanceInfoLine);
// then MOL blocks
if (is3kMode)
textBuffer.writeLine('M V30 ' + Kekule.IO.Mdl3kUtils.get3kBlockStartTag('REACTANT'));
for (var i = 0; i < reaction.getReactantCount(); ++i)
{
this.writeMolDelimiterLine(textBuffer);
this.writeMolBlock(reaction.getReactantAt(i), textBuffer);
}
if (is3kMode)
textBuffer.writeLine('M V30 ' + Kekule.IO.Mdl3kUtils.get3kBlockEndTag('REACTANT'));
if (is3kMode)
textBuffer.writeLine('M V30 ' + Kekule.IO.Mdl3kUtils.get3kBlockStartTag('PRODUCT'));
for (var i = 0; i < reaction.getProductCount(); ++i)
{
this.writeMolDelimiterLine(textBuffer);
this.writeMolBlock(reaction.getProductAt(i), textBuffer);
}
if (is3kMode)
{
textBuffer.writeLine('M V30 ' + Kekule.IO.Mdl3kUtils.get3kBlockEndTag('PRODUCT'));
// total end tag
textBuffer.writeLine('M END');
}
}
});
/**
* Base abstract reader for MDL 2000 / 3000 format data.
* @class
* @augments Kekule.IO.ChemDataReader
*/
Kekule.IO.BaseMdlReader = Class.create(Kekule.IO.ChemDataReader,
/** @lends Kekule.IO.BaseMdlReader# */
{
/** @private */
CLASS_NAME: 'Kekule.IO.BaseMdlReader',
/** @private */
doReadData: function(data, dataType, format)
{
if (dataType != Kekule.IO.ChemDataType.TEXT) // can not understand data other than text
{
Kekule.error(/*Kekule.ErrorMsg.MDL_INPUT_DATATYPE_NOT_TEXT*/Kekule.$L('ErrorMsg.MDL_INPUT_DATATYPE_NOT_TEXT'));
return null;
}
else
{
return this.doReadMdlData(data);
}
},
/**
* Do actual work of reading MDL data.
* Descendants should override this method.
* @param {String} data
* @returns {Kekule.ChemObject}
* @private
*/
doReadMdlData: function(data)
{
// do nothing here
return null;
}
});
/**
* Base abstract writer for MDL 2000 / 3000 format text data.
* @class
* @augments Kekule.IO.ChemDataWriter
*
* @property {Int} mdlVersion Output format. V2000 and V3000 has totally different data structures.
* @property {Int} coordMode Output 2D or 3D coordinate for molecule.
*/
Kekule.IO.BaseMdlWriter = Class.create(Kekule.IO.ChemDataWriter,
/** @lends Kekule.IO.BaseMdlWriter# */
{
/** @private */
CLASS_NAME: 'Kekule.IO.BaseMdlWriter',
/** @private */
initialize: function($super, options)
{
$super(options);
if (!options)
options = {};
this.setMdlVersion(options.mdlVersion || Kekule.globalOptions.IO.mdl.mdlVersion);
this.setCoordMode(options.coordMode || Kekule.globalOptions.IO.mdl.coordMode);
},
/** @private */
initProperties: function()
{
this.defineProp('mdlVersion', {'dataType': DataType.INT, 'defaultValue': Kekule.IO.MdlVersion.V2000});
this.defineProp('coordMode', {'dataType': DataType.INT, 'defaultValue': Kekule.CoordMode.UNKNOWN});
},
/** @private */
doWriteData: function($super, obj, dataType, format)
{
var dtype = dataType || Kekule.IO.ChemDataType.TEXT;
if (dtype != Kekule.IO.ChemDataType.TEXT) // can not understand data other than text
{
Kekule.error(/*Kekule.ErrorMsg.MDL_OUTPUT_DATATYPE_NOT_TEXT*/Kekule.$L('ErrorMsg.MDL_OUTPUT_DATATYPE_NOT_TEXT'));
return null;
}
else
return $super(obj, dtype, format);
}
});
/**
* Reader for MOL 2000 / 3000 format text data.
* Use MolReader.readData() can retrieve a suitable Kekule.Molecule.
* Data fetch in should be a string.
* @class
* @augments Kekule.IO.BaseMdlReader
*/
Kekule.IO.MdlMolReader = Class.create(Kekule.IO.BaseMdlReader,
/** @lends Kekule.IO.MdlMolReader# */
{
/** @private */
CLASS_NAME: 'Kekule.IO.MdlMolReader',
/** @private */
doReadMdlData: function(data)
{
var reader = new Kekule.IO.MdlMoleculeReader();
return reader.readBlock(data, null);
}
});
/**
* Writer for MOL 2000 / 3000 format text data.
* Use molWriter.writeData(obj) to save Kekule object to MDL text content.
* @class
* @augments Kekule.IO.BaseMdlWriter
*/
Kekule.IO.MdlMolWriter = Class.create(Kekule.IO.BaseMdlWriter,
/** @lends Kekule.IO.MdlMolWriter# */
{
/** @private */
CLASS_NAME: 'Kekule.IO.MdlMolWriter',
/** @private */
doWriteData: function(obj, dataType, format)
{
/*
if (dataType != Kekule.IO.ChemDataType.TEXT) // can not understand data other than text
{
Kekule.error(Kekule.ErrorMsg.MDL_OUTPUT_DATATYPE_NOT_TEXT);
return null;
}
else
*/
{
var writer = new Kekule.IO.MdlMoleculeWriter(this.getMdlVersion(), this.getCoordMode());
return writer.writeBlock(obj);
}
}
});
/**
* Reader for MOL 2000 / 3000 SD (structure-data) format text data.
* Data fetch in should be a string.
* @class
* @augments Kekule.IO.BaseMdlReader
*/
Kekule.IO.MdlSdReader = Class.create(Kekule.IO.BaseMdlReader,
/** @lends Kekule.IO.MdlSdReader# */
{
/** @private */
CLASS_NAME: 'Kekule.IO.MdlSdReader',
/** @private */
doReadMdlData: function(data)
{
{
var reader = new Kekule.IO.MdlStructDataReader();
return reader.readBlock(data, null);
}
}
});
/**
* Writer for MOL 2000 / 3000 SD (structure-data) format text data.
* @class
* @augments Kekule.IO.BaseMdlWriter
*/
Kekule.IO.MdlSdWriter = Class.create(Kekule.IO.BaseMdlWriter,
/** @lends Kekule.IO.MdlSdWriter# */
{
/** @private */
CLASS_NAME: 'Kekule.IO.MdlSdWriter',
/** @private */
doWriteData: function(obj, dataType, format)
{
var writer = new Kekule.IO.MdlStructDataWriter(this.getMdlVersion(), this.getCoordMode());
return writer.writeBlock(obj);
}
});
/**
* Reader for RXN 2000/3000 format text data.
* Use RxnReader.readData() can retrieve a suitable Kekule.Reaction.
* Data fetch in should be a string.
* @class
* @augments Kekule.IO.BaseMdlReader
*/
Kekule.IO.MdlRxnReader = Class.create(Kekule.IO.BaseMdlReader,
/** @lends Kekule.IO.MdlRxnReader# */
{
/** @private */
CLASS_NAME: 'Kekule.IO.MdlRxnReader',
/** @private */
doReadMdlData: function(data)
{
var reader = new Kekule.IO.MdlReactionReader();
return reader.readBlock(data, null);
}
});
/**
* Writer for RXN 2000 / 3000 format text data.
* Use RxnReader.writeData(obj) to save a Kekule.Reaction to MDL V2000 or 3000 text.
* @class
* @augments Kekule.IO.BaseMdlWriter
*/
Kekule.IO.MdlRxnWriter = Class.create(Kekule.IO.BaseMdlWriter,
/** @lends Kekule.IO.MdlRxnWriter# */
{
/** @private */
CLASS_NAME: 'Kekule.IO.MdlRxnWriter',
/** @private */
doWriteData: function(obj, dataType, format)
{
/*
if (dataType != Kekule.IO.ChemDataType.TEXT) // can not understand data other than text
{
Kekule.error(Kekule.ErrorMsg.MDL_OUTPUT_DATATYPE_NOT_TEXT);
return null;
}
else
*/
{
var writer = new Kekule.IO.MdlReactionWriter(this.getMdlVersion(), this.getCoordMode());
return writer.writeBlock(obj);
}
}
});
/**
* Reader for MOL or RXN 2000/3000 format text data.
* Use MdlReader.readData() can retrieve a suitable Kekule object.
* Data fetch in should be a string.
* @class
* @augments Kekule.IO.ChemDataReader
*/
Kekule.IO.MdlReader = Class.create(Kekule.IO.ChemDataReader,
/** @lends Kekule.IO.MdlReader# */
{
/** @private */
CLASS_NAME: 'Kekule.IO.MdlReader',
/** @private */
doReadData: function(data, dataType, format)
{
if (dataType != Kekule.IO.ChemDataType.TEXT) // can not understand data other than text
{
Kekule.error(/*Kekule.ErrorMsg.MDL_INPUT_DATATYPE_NOT_TEXT*/Kekule.$L('ErrorMsg.MDL_INPUT_DATATYPE_NOT_TEXT'));
return null;
}
else
{
var reader;
// check first 4 chars of data, $RXN means reaction, otherwise, MOL
var tag = data.substr(0, 4);
if (tag == '$RXN')
reader = new Kekule.IO.MdlReactionReader();
else
reader = new Kekule.IO.MdlMoleculeReader();
return reader.readBlock(data, null);
}
}
});
/**
* A general class to write MOL or RXN 2000/3000 format text data.
* Use MdlWriter.writeData() to save a reaction or molecule.
* @class
* @augments Kekule.IO.ChemDataWriter
*/
Kekule.IO.MdlWriter = Class.create(Kekule.IO.ChemDataWriter,
/** @lends Kekule.IO.MdlWriter# */
{
/** @private */
CLASS_NAME: 'Kekule.IO.MdlWriter',
/** @private */
initialize: function($super, options)
{
$super(options);
var op = options || {};
this.setMdlVersion(op.mdlVersion || Kekule.globalOptions.IO.mdl.mdlVersion);
this.setCoordMode(op.coordMode || Kekule.globalOptions.IO.mdl.coordMode);
},
/** @private */
initProperties: function()
{
this.defineProp('mdlVersion', {'dataType': DataType.INT, 'defaultValue': Kekule.IO.MdlVersion.V2000});
this.defineProp('coordMode', {'dataType': DataType.INT, 'defaultValue': Kekule.CoordMode.UNKNOWN});
},
/** @private */
doWriteData: function(obj, dataType, format)
{
var writer;
if (obj instanceof Kekule.Reaction)
writer = new Kekule.IO.MdlRxnWriter(this.getMdlVersion(), this.getCoordMode());
else if (obj instanceof Kekule.StructureFragment)
writer = new Kekule.IO.MdlMolWriter(this.getMdlVersion(), this.getCoordMode());
else
{
var className = (obj && obj.getClassName)? obj.getClassName(): typeof(obj);
Kekule.error(/*Kekule.ErrorMsg.UNABLE_TO_OUTPUT_AS_MDL*/Kekule.$L('ErrorMsg.UNABLE_TO_OUTPUT_AS_MDL').format(className));
return null;
}
if (writer)
return writer.writeData(obj);
}
});
(function ()
{
// register chem data formats
var molFmtId = 'mol';
var rxnFmtId = 'rxn';
var sdFmtId = 'sd';
var mol3kFmtId = 'mol3k';
var rxn3kFmtId = 'rxn3k';
Kekule.IO.DataFormat.MOL = molFmtId;
Kekule.IO.DataFormat.RXN = rxnFmtId;
Kekule.IO.DataFormat.SD = sdFmtId;
Kekule.IO.DataFormat.MOL3K = mol3kFmtId;
Kekule.IO.DataFormat.RXN3K = rxn3kFmtId;
// extents mime type consts
Kekule.IO.MimeType.MDL_MOL = 'chemical/x-mdl-molfile';
Kekule.IO.MimeType.MDL_RXN = 'chemical/x-mdl-rxnfile';
Kekule.IO.MimeType.MDL_SD = 'chemical/x-mdl-sdfile';
/*
Kekule.IO.DataFormatsManager.register('mol', 'chemical/x-mdl-molfile', 'mol',
Kekule.IO.ChemDataType.TEXT, 'MDL Mol 2000/3000 format');
Kekule.IO.DataFormatsManager.register('rxn', 'chemical/x-mdl-rxnfile', 'rxn',
Kekule.IO.ChemDataType.TEXT, 'MDL Reaction 2000/3000 format');
Kekule.IO.DataFormatsManager.register('sd', 'chemical/x-mdl-sdfile', ['sd', 'sdf'],
Kekule.IO.ChemDataType.TEXT, 'MDL Structure-Data format');
var molFmtId = Kekule.IO.DataFormatsManager.findFormatId('chemical/x-mdl-molfile');
var rxnFmtId = Kekule.IO.DataFormatsManager.findFormatId('chemical/x-mdl-rxnfile');
var sdFmtId = Kekule.IO.DataFormatsManager.findFormatId('chemical/x-mdl-sdfile');
*/
Kekule.IO.DataFormatsManager.register(molFmtId, Kekule.IO.MimeType.MDL_MOL, 'mol',
Kekule.IO.ChemDataType.TEXT, 'MDL Mol 2000 format');
Kekule.IO.DataFormatsManager.register(rxnFmtId, Kekule.IO.MimeType.MDL_RXN, 'rxn',
Kekule.IO.ChemDataType.TEXT, 'MDL Reaction 2000 format');
Kekule.IO.DataFormatsManager.register(sdFmtId, Kekule.IO.MimeType.MDL_SD, ['sd', 'sdf'],
Kekule.IO.ChemDataType.TEXT, 'MDL Structure-Data format');
Kekule.IO.DataFormatsManager.register(mol3kFmtId, Kekule.IO.MimeType.MDL_MOL, 'mol',
Kekule.IO.ChemDataType.TEXT, 'MDL Mol 3000 format');
Kekule.IO.DataFormatsManager.register(rxn3kFmtId, Kekule.IO.MimeType.MDL_RXN, 'rxn',
Kekule.IO.ChemDataType.TEXT, 'MDL Reaction 3000 format');
// register ChemData reader and writer
Kekule.IO.ChemDataReaderManager.register('MDL-mol', Kekule.IO.MdlMolReader, [molFmtId, mol3kFmtId]);
Kekule.IO.ChemDataReaderManager.register('MDL-rxn', Kekule.IO.MdlRxnReader, [rxnFmtId, rxn3kFmtId]);
Kekule.IO.ChemDataReaderManager.register('MDL-general', Kekule.IO.MdlReader, [molFmtId, mol3kFmtId, rxnFmtId, rxn3kFmtId]);
Kekule.IO.ChemDataReaderManager.register('MDL-sd', Kekule.IO.MdlSdReader, sdFmtId);
var suitableClasses = [Kekule.StructureFragment, Kekule.ChemObjList, Kekule.ChemStructureObjectGroup, Kekule.ChemSpaceElement, Kekule.ChemSpace];
Kekule.IO.ChemDataWriterManager.register('MDL-mol', Kekule.IO.MdlMolWriter, /*[Kekule.StructureFragment]*/suitableClasses, molFmtId);
Kekule.IO.ChemDataWriterManager.register('MDL-mol3k', Kekule.IO.MdlMolWriter, /*[Kekule.StructureFragment]*/suitableClasses, mol3kFmtId, {'createOptions': {'mdlVersion': Kekule.IO.MdlVersion.V3000}});
Kekule.IO.ChemDataWriterManager.register('MDL-rxn', Kekule.IO.MdlRxnWriter, [Kekule.Reaction], rxnFmtId);
Kekule.IO.ChemDataWriterManager.register('MDL-rxn3k', Kekule.IO.MdlRxnWriter, [Kekule.Reaction], rxn3kFmtId);
//Kekule.IO.ChemDataWriterManager.register('MDL-general', Kekule.IO.MdlWriter, [Kekule.StructureFragment, Kekule.Reaction], [molFmtId, mol3kFmtId, rxnFmtId, rxn3kFmtId]);
Kekule.IO.ChemDataWriterManager.register('MDL-sd', Kekule.IO.MdlSdWriter, suitableClasses, sdFmtId);
/*
TODO: MDL 2000 and 3000 have same MIME type, so they are registered by same format ID
TODO: How to save object in different format separately?
*/
/*
// register ChemData reader and writer
Kekule.IO.ChemDataReaderManager.register('mdl-general', Kekule.IO.MdlReader, {
'title': 'MDL format general',
'mimeType': '',
'fileExt': ['mol', 'rxn']
});
Kekule.IO.ChemDataReaderManager.register('mol', Kekule.IO.MdlMolReader, {
'title': 'MDL Mol format',
'mimeType': 'chemical/x-mdl-molfile',
'fileExt': 'mol'
});
Kekule.IO.ChemDataReaderManager.register('rxn', Kekule.IO.MdlRxnReader, {
'title': 'MDL Reaction format',
'mimeType': 'chemical/x-mdl-rxnfile',
'fileExt': 'rxn'
});
Kekule.IO.ChemDataWriterManager.register('mdl-general', Kekule.IO.MdlWriter,
[Kekule.ChemStructureFragment, Kekule.Reaction],
{
'title': 'MDL format general',
'mimeType': '',
'fileExt': ['mol', 'rxn']
});
Kekule.IO.ChemDataWriterManager.register('mol2000', Kekule.IO.MdlMolWriter,
[Kekule.ChemStructureFragment],
{
'createOptions': {'mdlVersion': Kekule.IO.MdlVersion.V2000},
'title': 'MDL Mol 2000 format',
'mimeType': 'chemical/x-mdl-molfile',
'fileExt': 'mol'
});
Kekule.IO.ChemDataWriterManager.register('mol3000', Kekule.IO.MdlMolWriter,
[Kekule.ChemStructureFragment],
{
'createOptions': {'mdlVersion': Kekule.IO.MdlVersion.V3000},
'title': 'MDL Mol 3000 format',
'mimeType': 'chemical/x-mdl-molfile',
'fileExt': 'mol'
});
Kekule.IO.ChemDataWriterManager.register('rxn2000', Kekule.IO.MdlRxnWriter,
[Kekule.Reaction],
{
'createOptions': {'mdlVersion': Kekule.IO.MdlVersion.V2000},
'title': 'MDL Reaction 2000 format',
'mimeType': 'chemical/x-mdl-rxnfile',
'fileExt': 'rxn'
});
Kekule.IO.ChemDataWriterManager.register('rxn3000', Kekule.IO.MdlRxnWriter,
[Kekule.Reaction],
{
'createOptions': {'mdlVersion': Kekule.IO.MdlVersion.V3000},
'title': 'MDL Reaction 3000 format',
'mimeType': 'chemical/x-mdl-rxnfile',
'fileExt': 'rxn'
});
*/
})();