/**
* @fileoverview
* Abstract root classes for concrete strcuture reader/writers of different structure formats.
* @author Partridge Jiang
*/
/*
* requires /lan/classes.js
* requires /core/kekule.common.js
* requires /utils/kekule.utils.js
* requires /xbrowsers/kekule.x.js
*/
(function(){
/*
* Root object of I/O default options
* @object
*/
Kekule.globalOptions.add('IO', {});
/**
* Name space for IO package of Kekule.
* @namespace
*/
Kekule.IO = {};
/**
* Enumeration of possible type of input data.
* @class
*/
Kekule.IO.ChemDataType = {
/** Plain Text, e.g. MOL data. */
TEXT: 'text',
/** DOM Structure, e.g. CML data */
DOM: 'dom',
/** JSON Object */
JSON: 'json',
/** Binary data */
BINARY: 'bin',
/** Other, not used now */
OTHER: 'other',
/** Unknown type, usually treat as binary. */
UNKNOWN: 'unknown',
/**
* Check if type is in binary format.
* @param {Int} dataType
* @returns {Bool}
*/
isBinaryType: function(dataType)
{
var T = Kekule.IO.ChemDataType;
return (!dataType) || (dataType === T.BINARY)
|| (dataType === T.OTHER) || (dataType === T.UNKNOWN);
}
};
/**
* Enumeration of common data format ids.
* @class
*/
Kekule.IO.DataFormat = {
};
/**
* Enumeration of common MIME types.
* @class
*/
Kekule.IO.MimeType = {
TEXT: 'text/plain',
HTML: 'text/html',
XML: 'text/xml',
JSON: 'application/json',
JAVASCRIPT: 'application/javascript',
GIF: 'image/gif',
JPEG: 'image/jpeg',
PNG: 'image/png',
XPNG: 'image/x-png',
OCTSTREAM: 'application/octet-stream'
};
/**
* Manager class of data formats.
* Generally data format item is a hash containing the following fields:
* {
* id: String, unique ID of format.
* dataType: type of data, text, binary or other.
* fileExts: Array, possible file extension associated with this format.
* mimeType: String, MIME type associated with this format.
* }
* @class
*/
Kekule.IO.DataFormatsManager = {
/** @private */
_formats: {},
/**
* Register a new data format. If the mimeType already exists, settings will be merged.
* @param {String} id
* @param {String} mimeType
* @param {Array} fileExts
* @param {String} title
* @param {String} description
* @param {Hash} additionalInfo
*/
register: function(id, mimeType, fileExts, dataType, title, description, additionalInfo)
{
//var result = Kekule.IO.DataFormatsManager.findFormat(mimeType);
var result = null; // MDL 3000/2000 share the same mimeType, so can not use it to make unique
/*
if (result)
console.log('merge', result.fileExts, result.fileExts.length, fileExts, mimeType);
*/
if (!result)
result = FM._formats[id];
if (!result)
{
result = {'id': id};
FM._formats[id] = result;
}
result.mimeType = mimeType;
var exts = DataType.isArrayValue(fileExts)? fileExts: [fileExts];
if (!result.fileExts)
result.fileExts = exts;
else // merge
Kekule.ArrayUtils.pushUnique(result.fileExts, exts);
if (dataType && (dataType !== Kekule.IO.ChemDataType.UNKNOWN))
result.dataType = dataType;
result.title = title;
result.description = description;
if (additionalInfo)
result = Object.extend(result, additionalInfo);
return result;
},
/**
* Unregister a data format.
* @param {String} id
*/
unregister: function(id)
{
if (FM._formats[id])
delete FM._formats[id];
},
/**
* Returns all registered
*/
getAllIds: function()
{
return Kekule.ObjUtils.getOwnedFieldNames(FM._formats);
},
/**
* Returns format detail information. If id not found, null will be returned.
* @param {String} id
* @returns {Hash}
*/
getFormatInfo: function(id)
{
return FM._formats[id] || null;
},
/**
* Returns MIME type of format id.
* @param {String} id
* @returns {String}
*/
getMimeType: function(id)
{
var info = FM.getFormatInfo(id);
return info? info.mimeType: null;
},
/**
* Returns file extensions of format id.
* @param {String} id
* @returns {Array}
*/
getFileExts: function(id)
{
var info = FM.getFormatInfo(id);
return info? info.fileExts: null;
},
/**
* Find format detail item by mimeType or fileExt.
* @param {String} mimeType
* @param {String} fileExt
* @returns {Hash}
*/
findFormat: function(mimeType, fileExt)
{
if (!mimeType && !fileExt)
return null;
var ids = FM.getAllIds();
var matched = false;
for (var i = 0, l = ids.length; i < l; ++i)
{
var info = FM.getFormatInfo(ids[i]);
/*
matched = (!mimeType || (mimeType === info.mimeType))
&& (!fileExt || (info.fileExts.indexOf(fileExt) >= 0));
*/
matched = (mimeType && (mimeType === info.mimeType));
if (!matched)
matched = (fileExt && (info.fileExts.indexOf(fileExt) >= 0));
if (matched)
return info;
}
return null;
},
/**
* Find format ID by mimeType or fileExt.
* @param {String} mimeType
* @param {String} fileExt
* @returns {String}
*/
findFormatId: function(mimeType, fileExt)
{
var info = Kekule.IO.DataFormatsManager.findFormat(mimeType, fileExt);
return info? info.id: null;
}
};
/** @ignore */
var FM = Kekule.IO.DataFormatsManager;
/** @ignore */
Kekule.IO.dataFormatsManager = Kekule.IO.DataFormatsManager;
/**
* Abstract root class for all chemistry data readers.
* @class
* @augments ObjectEx
* @param {Hash} options Some additional params passed to reader.
*/
Kekule.IO.ChemDataReader = Class.create(ObjectEx,
/** @lends Kekule.IO.ChemDataReader# */
{
/** @constructs */
initialize: function($super, options)
{
$super();
},
/** @private */
CLASS_NAME: 'Kekule.IO.ChemDataReader',
/*
* Read from data, create related instance and encapsulation the instance inside a {@link Kekule.ChemDocument}.
* @param {Variant} data
* @param {String} dataType Type of data, value should fom {@link Kekule.IO.ChemDataType}.
* @param {String} format Format ID.
* @returns {Kekule.ChemDocument} Instance created by data.
*/
/*
readDocument: function(data, dataType, format)
{
return this.doReadDocument(data, dataType, format);
},
*/
/*
* Do actual work for {@link Kekule.IO.ChemDataReader#readDocument}. Descendants should override this method.
* @param {Variant} data
* @param {String} dataType Type of data, value should fom {@link Kekule.IO.ChemDataType}.
* @param {String} format Format ID.
* @returns {Kekule.ChemDocument} Instance created by data.
*/
/*
doReadDocument: function(data, dataType, format)
{
var doc;
var r = this.readData(data, dataType, format);
if (r && r.setOwner)
{
doc = new Kekule.ChemDocument();
doc.setDocObj(r);
}
return doc;
},
*/
/**
* Read from data and return a related instance.
* @param {Variant} data
* @param {String} dataType Type of data, value should fom {@link Kekule.ChemStructureDataType}.
* @param {String} format Format ID.
* @param {Hash} options Additional options to read data. Different reader may have different options.
* @returns {Variant} Instance created by data.
*/
readData: function(data, dataType, format, options)
{
if (!dataType) // auto detect
{
var finfo = Kekule.IO.DataFormatsManager.getFormatInfo(format);
dataType = finfo? finfo.dataType: null;
if (!dataType)
dataType = (typeof(data) === 'string')?
Kekule.IO.ChemDataType.TEXT:
(data.getElementsByTagName? Kekule.IO.ChemDataType.DOM: Kekule.IO.ChemDataType.BINARY );
}
var result = this.doReadData(data, dataType, format, options || {});
if ((result instanceof Kekule.ChemObject) && (result.getSrcInfo))
{
var info = result.getSrcInfo();
info.data = data;
info.dataType = dataType;
var formatDetail = Kekule.IO.DataFormatsManager.getFormatInfo(format);
if (formatDetail)
{
info.format = format;
info.mimeType = formatDetail.mimeType;
info.possibleFileExts = formatDetail.fileExts;
}
//console.log('set src info', info);
}
return result;
},
/**
* Do actual work for {@link Kekule.IO.ChemDataReader#readData}. Descendants should override this method.
* @param {Variant} data
* @param {String} dataType Type of data, value should fom {@link Kekule.IO.ChemDataType}.
* @param {String} format Format ID.
* @param {Hash} options Additional options to read data. Different reader may have different options.
* @returns {Variant} Instance created by data.
*/
doReadData: function(data, dataType, format, options)
{
// do nothing here
}
});
/**
* Abstract root class for all chemistry data writers.
* @class
* @augments ObjectEx
* @param {Hash} options Some additional params passed to reader.
*/
Kekule.IO.ChemDataWriter = Class.create(ObjectEx,
/** @lends Kekule.IO.ChemDataWriter# */
{
/** @private */
CLASS_NAME: 'Kekule.IO.ChemDataWriter',
/** @constructs */
initialize: function($super, options)
{
$super();
},
/*
* Read document object of {@link Kekule.ChemDocument} and write it to proper data form.
* @param {@link Kekule.ChemDocument} doc Document to write.
* @param {String} dataType Type of data, value should fom {@link Kekule.IO.ChemDataType}.
* @param {String} format Format ID.
* @returns {Variant} Data output, the type of data is decided by dataType param.
*/
/*
writeDocument: function(doc, dataType, format)
{
return this.doWriteDocument(doc, dataType, format);
},
*/
/*
* Do actual work for {@link Kekule.IO.ChemDataReader#writeDocument}. Descendants should override this method.
* @param {@link Kekule.ChemDocument} doc Document to write.
* @param {String} dataType Type of data, value should fom {@link Kekule.IO.ChemDataType}.
* @param {String} format Format ID.
* @returns {Variant} Data output, the type of data is decided by dataType param.
*/
/*
doWriteDocument: function(doc, dataType, format)
{
return this.writeData(doc.docObj, dataType, format);
},
*/
/**
* Write Kekule object to data.
* @param {Kekule.ChemObject} obj Object to write
* @param {String} dataType Type of data, value should fom {@link Kekule.IO.ChemDataType}.
* @param {String} format Format ID.
* @param {Hash} options Additional options to write data. Different writer may have different options.
* @returns {Variant} Data output, the type of data is decided by dataType param.
*/
writeData: function(obj, dataType, format, options)
{
//var dtype = dataType || Kekule.IO.ChemDataType.TEXT;
if (!dataType) // auto detect
{
var finfo = Kekule.IO.DataFormatsManager.getFormatInfo(format);
dataType = finfo? finfo.dataType: null;
}
return this.doWriteData(obj, dataType, format, options || {});
},
/**
* Do actual work for {@link Kekule.IO.ChemDataReader#writeData}. Descendants should override this method.
* @param {Kekule.ChemObject} obj Object to write
* @param {String} dataType Type of data, value should fom {@link Kekule.IO.ChemDataType}.
* @param {String} format Format ID.
* @param {Hash} options Additional options to write data. Different writer may have different options.
* @returns {Variant} Data output, the type of data is decided by dataType param.
* @private
*/
doWriteData: function(obj, dataType, format, options)
{
// do nothing here
}
});
/**
* A manager to create suitable data reader.
* @class
*/
Kekule.IO.ChemDataReaderManager = {
/**
* Stores registered reader information. Each item including the following fields:
* {
* id: String,
* readerClass: Class,
* instances: Object // reader instance, null at first
* additionalInfos...
* }
* @private
*/
_readers: [],
/**
* Register a data reader.
* @param {String} id A UID string for reader.
* @param {Class} readerClass Class of reader.
* @param {Variant} formatId String or Array, associated format IDs.
* @param {Hash} additionalInfo More information on this reader class. Can include the following fields:
* {
* {Hash} createOptions: hash passed into reader's constructor.
* (String) title: Reader title,
* {String} formatId: id of data format
* //(String) mimeType
* //(Variant) fileExt: if load from a file, the file ext. Can be a string or Array of string.
* }
*/
register: function(id, readerClass, formatId, additionalInfo)
{
if (!id || !readerClass || !formatId || (DataType.isArrayValue(formatId) && !formatId.length)) // empty format
return;
if (Kekule.IO.ChemDataReaderManager.getReaderInfoById(id)) // id can not be duplicate
{
Kekule.raise(/*Kekule.ErrorMsg.READER_ID_ALREADY_EXISTS*/Kekule.$L('ErrorMsg.READER_ID_ALREADY_EXISTS'));
return null;
}
var item = {
'id': id,
'readerClass': readerClass,
'formatId': DataType.isArrayValue(formatId)? formatId: [formatId]
};
item = Object.extend(item, additionalInfo);
Kekule.IO.ChemDataReaderManager._readers.push(item);
return item;
},
/**
* Unregister a data reader.
* @param {String} id A UID string for reader.
*/
unregister: function(id)
{
var index = -1;
var readers = Kekule.IO.ChemDataReaderManager._readers;
for (var i = 0, l = readers.length; i < l; ++i)
{
var currId = readers[i].id;
if (currId === id)
{
index = i;
break;
}
}
if (index >= 0)
{
var reader = readers[index];
readers.splice(index, 1);
return reader;
}
else
return null;
},
/**
* Returns all file format IDs that has corresponding reader.
* @returns {Array} Array of format id.
*/
getAllReadableFormatIds: function()
{
var result = [];
var readers = Kekule.IO.ChemDataReaderManager._readers;
for (var i = 0, l = readers.length; i < l; ++i)
{
var item = readers[i];
var fids = item.formatId;
//result = result.concat(fids || []);
Kekule.ArrayUtils.pushUnique(result, fids);
}
return result;
},
/**
* Returns all file formats that has corresponding reader.
* @returns {Array} Array of format object.
*/
getAllReadableFormats: function()
{
var result = [];
/*
var readers = Kekule.IO.ChemDataReaderManager._readers;
for (var i = 0, l = readers.length; i < l; ++i)
{
var item = readers[i];
var fids = item.formatId;
for (var j = 0, k = fids.length; j < k; ++j)
{
var fid = fids[j];
var info = FM.getFormatInfo(fid);
if (info)
result.push(info);
}
}
*/
var ids = Kekule.IO.ChemDataReaderManager.getAllReadableFormatIds();
for (var i = 0, l = ids.length; i < l; ++i)
{
var info = FM.getFormatInfo(ids[i]);
if (info)
result.push(info);
}
return result;
},
/**
* Get all available reader infos by condition provided and be suitable for targetClass.
* For example: Kekule.IO.ChemDataReaderManager.getAvailableReaderInfos({'id': 'mol'});
* @param {Hash} condition
* @returns {Array}
*/
getAvailableReaderInfos: function(condition)
{
var result = [];
var rs = Kekule.IO.ChemDataReaderManager._readers;
for (var i = rs.length - 1; i >=0; --i)
{
if (Kekule.ObjUtils.match(rs[i], condition))
{
result.push(rs[i]);
}
}
return result;
},
/**
* Get reader information by condition provided.
* For example: Kekule.IO.ChemDataWriterManager.getReaderInfo({'formatId': 'cml'});
* @param {Hash} condition
* @returns {Hash}
*/
getReaderInfo: function(condition)
{
var rs = Kekule.IO.ChemDataReaderManager._readers;
for (var i = rs.length - 1; i >=0; --i)
{
if (Kekule.ObjUtils.match(rs[i], condition))
return rs[i];
}
return null;
},
/**
* Get reader information by Id.
* @param {String} id
* @returns {Hash}
*/
getReaderInfoById: function(id)
{
return Kekule.IO.ChemDataReaderManager.getReaderInfo({'id': id});
},
/**
* Get reader information by data format id.
* @param {String} formatId
* @param {Hash} otherConditions
* @returns {Hash}
*/
getReaderInfoByFormat: function(formatId, otherConditions)
{
var rs = Kekule.IO.ChemDataReaderManager._readers;
for (var i = rs.length - 1; i >=0; --i)
{
if ((!otherConditions) || Kekule.ObjUtils.match(rs[i], otherConditions))
{
if (rs[i].formatId.indexOf(formatId) >= 0)
return rs[i];
}
}
return null;
},
/**
* Get reader information by file ext.
* @param {String} fileExt
* @param {Hash} otherConditions
* @returns {Hash}
*/
getReaderInfoByFileExt: function(fileExt, otherConditions)
{
/*
var rs = Kekule.IO.ChemDataReaderManager._readers;
for (var i = rs.length - 1; i >=0; --i)
{
if ((!otherConditions) || Kekule.ObjUtils.match(rs[i], otherConditions))
{
if (rs[i].fileExt == fileExt)
return rs[i];
else if (rs[i].fileExt.indexOf && (rs[i].fileExt.indexOf(fileExt) >= 0))
return rs[i];
}
}
return null;
*/
var fid = Kekule.IO.DataFormatsManager.findFormatId(null, fileExt);
return fid? Kekule.IO.ChemDataReaderManager.getReaderInfoByFormat(fid, otherConditions): null;
},
/** @private */
createReaderOfInfo: function(info)
{
return new info.readerClass(info.createOptions);
},
/** @private */
getReaderOfInfo: function(info)
{
if (!info.instance)
info.instance = Kekule.IO.ChemDataReaderManager.createReaderOfInfo(info);
return info.instance;
},
/**
* Create a new reader instance by condition.
* @param {Hash} condition
* @returns {Kekule.IO.ChemDataReader}
*/
createReader: function(condition)
{
var info = Kekule.IO.ChemDataReaderManager.getReaderInfo(condition);
if (info)
return Kekule.IO.ChemDataReaderManager.createReaderOfInfo(info);
},
/**
* Get a reusable reader instance by condition.
* @param {Hash} condition
* @returns {Kekule.IO.ChemDataReader}
*/
getReader: function(condition)
{
var info = Kekule.IO.ChemDataReaderManager.getReaderInfo(condition);
if (info)
return Kekule.IO.ChemDataReaderManager.getReaderOfInfo(info);
},
/**
* Create a new reader instance by id.
* @param {String} id
* @returns {Kekule.IO.ChemDataReader}
*/
createReaderById: function(id)
{
return Kekule.IO.ChemDataReaderManager.createReader({'id': id});
},
/**
* Get a reusable reader instance by id.
* @param {String} id
* @returns {Kekule.IO.ChemDataReader}
*/
getReaderById: function(id)
{
return Kekule.IO.ChemDataReaderManager.getReader({'id': id});
},
/**
* Create new reader instance by formatId.
* @param {String} formatId
* @param {Hash} otherConditions
* @returns {Kekule.IO.ChemDataReader}
*/
createReaderByFormat: function(formatId, otherConditions)
{
var info = Kekule.IO.ChemDataReaderManager.getReaderInfoByFormat(formatId, otherConditions);
return info? IO.ChemDataReaderManager.createReaderOfInfo(info): null;
},
/**
* Get reader instance by format Id.
* @param {String} fileExt
* @param {Hash} otherConditions
* @returns {Kekule.IO.ChemDataReader}
*/
getReaderByFormat: function(formatId, otherConditions)
{
var info = Kekule.IO.ChemDataReaderManager.getReaderInfoByFormat(formatId, otherConditions);
return info? Kekule.IO.ChemDataReaderManager.getReaderOfInfo(info): null;
},
/**
* Create reader instance by file ext.
* @param {String} fileExt
* @param {Hash} otherConditions
* @returns {Kekule.IO.ChemDataReader}
*/
createReaderByFileExt: function(fileExt, otherConditions)
{
var info = Kekule.IO.ChemDataReaderManager.getReaderInfoByFileExt(fileExt, otherConditions);
return info? Kekule.IO.ChemDataReaderManager.createReaderOfInfo(info): null;
},
/**
* Get reader instance by file ext.
* @param {String} fileExt
* @param {Hash} otherConditions
* @returns {Kekule.IO.ChemDataReader}
*/
getReaderByFileExt: function(fileExt, otherConditions)
{
var info = Kekule.IO.ChemDataReaderManager.getReaderInfoByFileExt(fileExt, otherConditions);
return info? Kekule.IO.ChemDataReaderManager.getReaderOfInfo(info): null;
},
/**
* Create a new reader instance by MIME type.
* @param {String} mimeType
* @returns {Kekule.IO.ChemDataReader}
*/
createReaderByMimeType: function(mimeType)
{
//return Kekule.IO.ChemDataReaderManager.createReader({'mimeType': mimeType});
var fid = Kekule.IO.DataFormatsManager.findFormatId(mimeType, null);
return fid? Kekule.IO.ChemDataReaderManager.createReaderByFormat(fid): null;
},
/**
* Get a reusable reader instance by MIME type.
* @param {String} mimeType
* @returns {Kekule.IO.ChemDataReader}
*/
getReaderByMimeType: function(mimeType)
{
//return Kekule.IO.ChemDataReaderManager.getReader({'mimeType': mimeType});
var fid = Kekule.IO.DataFormatsManager.findFormatId(mimeType, null);
return fid? Kekule.IO.ChemDataReaderManager.getReaderByFormat(fid): null;
}
};
/**
* A manager to create suitable data writer.
* @class
*/
Kekule.IO.ChemDataWriterManager = {
/**
* Stores registered writer information. Each item including the following fields:
* {
* id: String,
* srcClass: Class,
* writerClass: Class,
* instances: Object // reader instance, null at first
* additionalInfos...
* }
* @private
*/
_writers: [],
/**
* Register a data writer.
* @param {String} id A UID string for writer.
* @param {Class} writerClass Class of writer.
* @param {Array} srcClasses Instance of which classes can be written by this writer.
* @param {Variant} formatId Data format, string or array.
* @param {Hash} additionalInfo More information on this reader class. Can include the following fields:
* {
* {Hash} createOptions: hash passed into writer's constructor.
* (String) title: Writer title,
* (String) mimeType
* (String) fileExt: if write to a file, the file ext.
* }
*/
register: function(id, writerClass, srcClasses, formatId, additionalInfo)
{
if (!id || !writerClass || !formatId || (DataType.isArrayValue(formatId) && !formatId.length)) // empty format
return;
if (Kekule.IO.ChemDataWriterManager.getWriterInfoById(id)) // id can not be duplicate
{
Kekule.raise(/*Kekule.ErrorMsg.WRITER_ID_ALREADY_EXISTS*/Kekule.$L('ErrorMsg.WRITER_ID_ALREADY_EXISTS'));
return null;
}
var item = {
'id': id,
'writerClass': writerClass,
'srcClasses': srcClasses,
'formatId': DataType.isArrayValue(formatId)? formatId: [formatId]
};
item = Object.extend(item, additionalInfo);
Kekule.IO.ChemDataWriterManager._writers.push(item);
return item;
},
/**
* Unregister a data writer.
* @param {String} id A UID string for reader.
*/
unregister: function(id)
{
var index = -1;
var writers = Kekule.IO.ChemDataWriterManager._writers;
for (var i = 0, l = writers.length; i < l; ++i)
{
var currId = writers[i].id;
if (currId === id)
{
index = i;
break;
}
}
if (index >= 0)
{
var writer = writers[index];
writers.splice(index, 1);
return writer;
}
else
return null;
},
/**
* Returns all file format IDs that has corresponding writer.
* @returns {Array} Array of format id.
*/
getAllWritableFormatIds: function()
{
var result = [];
var writers = Kekule.IO.ChemDataWriterManager._writers;
for (var i = 0, l = writers.length; i < l; ++i)
{
var item = writers[i];
var fids = item.formatId;
//result = result.concat(fids || []);
Kekule.ArrayUtils.pushUnique(result, fids);
}
return result;
},
/**
* Returns all file formats that has corresponding writer.
* @returns {Array} Array of format object.
*/
getAllWritableFormats: function()
{
var result = [];
var ids = Kekule.IO.ChemDataWriterManager.getAllWritableFormatIds();
for (var i = 0, l = ids.length; i < l; ++i)
{
var info = FM.getFormatInfo(ids[i]);
if (info)
result.push(info);
}
return result;
},
/**
* Get all available writer infos by condition provided and suitble for srcObj.
* For example: Kekule.IO.ChemDataWriterManager.getWriterInfo({'id': 'mol'});
* @param {Hash} condition
* @param {Variant} srcObjOrClass
* @returns {Array}
*/
getAvailableWriterInfos: function(condition, srcObjOrClass)
{
var result = [];
var srcClass = ClassEx.isClass(srcObjOrClass)? srcObjOrClass:
srcObjOrClass.getClass? srcObjOrClass.getClass():
srcObjOrClass? null: // null, src set but no class found, special marked
undefined;
var ws = Kekule.IO.ChemDataWriterManager._writers;
for (var i = ws.length - 1; i >=0; --i)
{
if (Kekule.ObjUtils.match(ws[i], condition))
{
if (srcClass !== undefined)
{
if (srcClass)
{
for (var j = 0, k = ws[i].srcClasses.length; j < k; ++j)
{
if (ClassEx.isOrIsDescendantOf(srcClass, ws[i].srcClasses[j]))
result.push(ws[i]);
}
}
}
else
result.push(ws[i]);
}
}
return result;
},
/**
* Get writer info by condition provided and suitble for srcObj.
* For example: Kekule.IO.ChemDataWriterManager.getWriterInfo({'id': 'mol'});
* @param {Hash} condition
* @param {Kekule.ChemObject} srcObj
* @returns {Hash}
*/
getWriterInfo: function(condition, srcObj)
{
var ws = Kekule.IO.ChemDataWriterManager._writers;
for (var i = ws.length - 1; i >=0; --i)
{
if (Kekule.ObjUtils.match(ws[i], condition))
{
if (srcObj)
{
for (var j = 0, k = ws[i].srcClasses.length; j < k; ++j)
{
if (srcObj instanceof ws[i].srcClasses[j])
return ws[i];
}
return null;
}
else
return ws[i];
}
}
return null;
},
/**
* Get writer information by Id.
* @param {String} id
* @param {Kekule.ChemObject} srcObj
* @returns {Hash}
*/
getWriterInfoById: function(id, srcObj)
{
return Kekule.IO.ChemDataWriterManager.getWriterInfo({'id': id}, srcObj);
},
/**
* Get writer information by data format id.
* @param {String} formatId
* @param {Hash} otherConditions
* @returns {Hash}
*/
getWriterInfoByFormat: function(formatId, otherConditions, srcObj)
{
/*
var condition = otherConditions || {};
condition.formatId = formatId;
return Kekule.IO.ChemDataWriterManager.getWriterInfo(condition, srcObj);
*/
var ws = Kekule.IO.ChemDataWriterManager._writers;
for (var i = ws.length - 1; i >=0; --i)
{
if ((!otherConditions) || Kekule.ObjUtils.match(ws[i], otherConditions))
{
if (ws[i].formatId.indexOf(formatId) >= 0)
{
if (srcObj)
{
for (var j = 0, k = ws[i].srcClasses.length; j < k; ++j)
{
if (srcObj instanceof ws[i].srcClasses[j])
return ws[i];
}
return null;
}
return ws[i];
}
}
}
return null;
},
/**
* Get writer information by file ext.
* @param {String} fileExt
* @param {Hash} otherConditions
* @param {Kekule.ChemObject} srcObj
* @returns {Hash}
*/
getWriterInfoByFileExt: function(fileExt, otherConditions, srcObj)
{
/*
var ws = Kekule.IO.ChemDataWriterManager._writers;
var result;
for (var i = ws.length - 1; i >=0; --i)
{
result = null;
if ((!otherConditions) || Kekule.ObjUtils.match(ws[i], otherConditions))
{
if (ws[i].fileExt == fileExt)
result = ws[i];
else if (ws[i].fileExt.indexOf && (ws[i].fileExt.indexOf(fileExt) >= 0))
result = ws[i];
}
if (result) // check srcObj
{
if (srcObj)
{
for (var j = 0, k = result.srcClasses; j < k; ++j)
{
if (srcObj instanceof result.srcClasses[j])
return result;
}
result = null;
}
else
return result;
}
}
return null;
*/
var fid = Kekule.IO.DataFormatsManager.findFormatId(null, fileExt);
return fid? Kekule.IO.ChemDataWriterManager.getWriterInfoByFormat(fid, otherConditions, srcObj): null;
},
/** @private */
createWriterOfInfo: function(info)
{
return new info.writerClass(info.createOptions);
},
/** @private */
getWriterOfInfo: function(info)
{
if (!info.instance)
info.instance = Kekule.IO.ChemDataWriterManager.createWriterOfInfo(info);
return info.instance;
},
/**
* Create a new writer instance by condition and suitable for srcObj.
* @param {Hash} condition
* @param {Kekule.ChemObject} srcObj
* @returns {Kekule.IO.ChemDataWriter}
*/
createWriter: function(condition, srcObj)
{
var info = Kekule.IO.ChemDataWriterManager.getWriterInfo(condition, srcObj);
if (info)
return Kekule.IO.ChemDataWriterManager.createWriterOfInfo(info);
else
return null;
},
/**
* Get a reusable writer instance by condition and suitable for srcObj.
* @param {Hash} condition
* @param {Kekule.ChemObject} srcObj
* @returns {Kekule.IO.ChemDataWriter}
*/
getWriter: function(condition, srcObj)
{
var info = Kekule.IO.ChemDataWriterManager.getWriterInfo(condition, srcObj);
if (info)
return Kekule.IO.ChemDataWriterManager.getWriterOfInfo(info);
else
return null;
},
/**
* Create a new writer instance by id and meet srcObj.
* @param {String} id
* @param {Kekule.ChemObject} srcObj
* @returns {Kekule.IO.ChemDataWriter}
*/
createWriterById: function(id, srcObj)
{
return Kekule.IO.ChemDataWriterManager.createWriter({'id': id}, srcObj);
},
/**
* Get a reusable writer instance by id and meet srcObj.
* @param {String} id
* @param {Kekule.ChemObject} srcObj
* @returns {Kekule.IO.ChemDataWriter}
*/
getWriterById: function(id, srcObj)
{
return Kekule.IO.ChemDataWriterManager.getWriter({'id': id}, srcObj);
},
/**
* Create new writer instance by formatId.
* @param {String} formatId
* @param {Hash} otherConditions
* @returns {Kekule.IO.ChemDataWriter}
*/
createWriterByFormat: function(formatId, otherConditions, srcObj)
{
var info = Kekule.IO.ChemDataWriterManager.getWriterInfoByFormat(formatId, otherConditions, srcObj);
return info? Kekule.IO.ChemDataWriterManager.createWriterOfInfo(info): null;
},
/**
* Get new writer instance by formatId.
* @param {String} formatId
* @param {Hash} otherConditions
* @returns {Kekule.IO.ChemDataWriter}
*/
getWriterByFormat: function(formatId, otherConditions, srcObj)
{
var info = Kekule.IO.ChemDataWriterManager.getWriterInfoByFormat(formatId, otherConditions, srcObj);
return info? Kekule.IO.ChemDataWriterManager.getWriterOfInfo(info): null;
},
/**
* Create writer instance by file ext.
* @param {String} fileExt
* @param {Hash} otherConditions
* @param {Kekule.ChemObject} srcObj
* @returns {Kekule.IO.ChemDataWriter}
*/
createWriterByFileExt: function(fileExt, otherConditions, srcObj)
{
var info = Kekule.IO.ChemDataWriterManager.getWriterInfoByFileExt(fileExt, otherConditions, srcObj);
return info? Kekule.IO.ChemDataWriterManager.createWriterOfInfo(info): null;
},
/**
* Get a reusbale writer instance by file ext.
* @param {String} fileExt
* @param {Hash} otherConditions
* @param {Kekule.ChemObject} srcObj
* @returns {Kekule.IO.ChemDataWriter}
*/
getWriterByFileExt: function(fileExt, otherConditions, srcObj)
{
var info = Kekule.IO.ChemDataWriterManager.getWriterInfoByFileExt(fileExt, otherConditions, srcObj);
return info? Kekule.IO.ChemDataWriterManager.getWriterOfInfo(info): null;
},
/**
* Create a new reader instance by MIME type.
* @param {String} mimeType
* @param {Kekule.ChemObject} srcObj
* @returns {Kekule.IO.ChemDataWriter}
*/
createWriterByMimeType: function(mimeType, srcObj)
{
//return Kekule.IO.ChemDataWriterManager.createWriter({'mimeType': mimeType});
var fid = Kekule.IO.DataFormatsManager.findFormatId(mimeType, null);
return fid? Kekule.IO.ChemDataWriterManager.createWriterByFormat(fid, null, srcObj): null;
},
/**
* Get a reusable new reader instance by MIME type.
* @param {String} mimeType
* @returns {Kekule.IO.ChemDataWriter}
*/
getWriterByMimeType: function(mimeType)
{
//return Kekule.IO.ChemDataWriterManager.getWriter({'mimeType': mimeType});
var fid = Kekule.IO.DataFormatsManager.findFormatId(mimeType, null);
return fid? Kekule.IO.ChemDataWriterManager.getWriterByFormat(fid, null, srcObj): null;
}
};
/**
* Load from content with certain format.
* @param {String} content
* @param {String} formatId
* @param {Hash} options Additional options to read data. Different data format may have different options.
* @returns {Kekule.ChemObject}
*/
Kekule.IO.loadFormatData = function(content, formatId, options)
{
var reader = Kekule.IO.ChemDataReaderManager.getReaderByFormat(formatId);
if (reader)
{
var result = reader.readData(content, null, formatId, options);
/*
if ((result instanceof Kekule.ChemObject) && (result.getSrcInfo))
{
var info = result.getSrcInfo();
info.mimeType = mimeType;
info.fileExt = fileExt;
info.url = url;
}
*/
//if (!result)
if (result === false) // read data failed
{
var msg = Kekule.$L('ErrorMsg.FAIL_TO_READ_FORMAT') + formatId;
Kekule.raise(msg);
}
return result;
}
else
{
var msg = /*Kekule.ErrorMsg.NO_SUITABLE_READER_FOR_FORMAT*/Kekule.$L('ErrorMsg.NO_SUITABLE_READER_FOR_FORMAT') + formatId;
Kekule.raise(msg);
return null;
}
};
/**
* Load from content with mimeType and create a new chem object.
* @param {String} content
* @param {String} mimeType
* @param {Hash} options Additional options to read data. Different data format may have different options.
* @returns {Kekule.ChemObject}
*/
Kekule.IO.loadMimeData = function(content, mimeType, options)
{
/*
var reader = Kekule.IO.ChemDataReaderManager.getReaderByMimeType(mimeType);
if (reader)
{
var result = reader.readData(content);
if ((result instanceof Kekule.ChemObject) && (result.getSrcInfo))
{
result.getSrcInfo().mimeType = mimeType;
}
}
else
{
Kekule.raise(Kekule.ErrorMsg.NO_SUITABLE_READER_FOR_MIMETYPE + mimeType);
return null;
}
*/
return Kekule.IO.loadTypedData(content, mimeType, null, options);
};
/**
* Load a typed content and create a new chem object, the type is recognized by mimeType or the file extension.
* @param {String} content
* @param {String} mimeType
* @param {String} url
* @param {Hash} options Additional options to read data. Different data format may have different options.
* @returns {Kekule.ChemObject}
*/
Kekule.IO.loadTypedData = function(content, mimeType, url, options)
{
//var reader;
var fileExt;
if (url)
{
fileExt = Kekule.UrlUtils.extractFileExt(url);
/*
if (!fileExt)
fileExt = urlOrFileExt;
else
url = urlOrFileExt;
*/
}
/*
if (mimeType)
reader = Kekule.IO.ChemDataReaderManager.getReaderByMimeType(mimeType);
if (!reader && fileExt)
{
reader = Kekule.IO.ChemDataReaderManager.getReaderByFileExt(fileExt);
}
if (reader)
{
var result = reader.readData(content);
if ((result instanceof Kekule.ChemObject) && (result.getSrcInfo))
{
var info = result.getSrcInfo();
if (mimeType)
info.mimeType = mimeType;
if (fileExt)
info.fileExt = fileExt;
if (url)
info.url = url;
}
return result;
}
*/
var formatId = Kekule.IO.DataFormatsManager.findFormatId(mimeType, mimeType? null: fileExt);
var result;
if (formatId)
result = Kekule.IO.loadFormatData(content, formatId, options);
//if (result)
if (result !== false) // read data success
{
if ((result instanceof Kekule.ChemObject) && (result.getSrcInfo))
{
var info = result.getSrcInfo();
if (mimeType)
info.mimeType = mimeType;
if (fileExt)
info.fileExt = fileExt;
if (url)
{
info.url = url;
info.fileName = url;
}
}
return result;
}
else
{
var msg = mimeType?
(/*Kekule.ErrorMsg.NO_SUITABLE_READER_FOR_MIMETYPE*/Kekule.$L('ErrorMsg.NO_SUITABLE_READER_FOR_MIMETYPE') + mimeType):
(/*Kekule.ErrorMsg.NO_SUITABLE_READER_FOR_FILEEXT*/Kekule.$L('ErrorMsg.NO_SUITABLE_READER_FOR_FILEEXT') + fileExt);
Kekule.raise(msg);
return null;
}
};
/**
* Load chem object from a File object.
* Note this function relies on FileApi support.
* @param {File} file
* @param {Function} callback Callback function when the file is loaded. Has two params (chemObj, success).
* @param {String} formatId If not set, format will be get from file name automatically.
* @param {Hash} options Additional options to read data. Different data format may have different options.
*/
Kekule.IO.loadFileData = function(file, callback, formatId, options)
{
if (Kekule.BrowserFeature.fileapi)
{
//try
{
var fileName = file.name;
var ext = Kekule.UrlUtils.extractFileExt(fileName);
var formatInfo;
if (!formatId)
{
formatInfo = Kekule.IO.DataFormatsManager.findFormat(null, ext);
}
else
formatInfo = Kekule.IO.DataFormatsManager.getFormatInfo(formatId);
if (!formatInfo)
{
var msg = /*Kekule.ErrorMsg.NO_SUITABLE_READER_FOR_FILEEXT*/Kekule.$L('ErrorMsg.NO_SUITABLE_READER_FOR_FILEEXT') + ext;
Kekule.raise(msg);
return;
}
//var isBinary = (formatInfo.dataType === Kekule.IO.ChemDataType.BINARY);
var isBinary = Kekule.IO.ChemDataType.isBinaryType(formatInfo.dataType);
// try open it the file by FileReader
var reader = new FileReader();
reader.onload = function(e)
{
var content = reader.result;
var chemObj = Kekule.IO.loadFormatData(content, formatInfo.id, options);
var info = chemObj.getSrcInfo();
info.fileName = fileName;
//var success = !!chemObj;
var success = (chemObj !== false);
callback(chemObj, success);
};
if (isBinary)
//reader.readAsBinaryString(file);
reader.readAsArrayBuffer(file);
else
reader.readAsText(file);
}
/*
catch(e)
{
console.error('EXTRA ERROR HERE');
Kekule.error(e);
}
*/
}
else
{
Kekule.error(/*Kekule.ErrorMsg.FILE_API_NOT_SUPPORTED*/Kekule.$L('ErrorMsg.FILE_API_NOT_SUPPORTED'));
}
};
/**
* Load chem object from a URL.
* Note this function relies on AJAX support.
* @param {String} fileUrl
* @param {Function} callback Callback function when the file is loaded. Has two params (chemObj, success).
* @param {String} formatId If not set, format will be get from file name automatically.
* @param {Hash} options Additional options to read data. Different data format may have different options.
*/
Kekule.IO.loadUrlData = function(fileUrl, callback, formatId, options)
{
if (Kekule.Ajax)
{
Kekule.Ajax.sendRequest(fileUrl, function(data, requestObj, success){
if (data && success)
{
// try resolve file format
var formatInfo;
if (formatId)
formatInfo = Kekule.IO.DataFormatsManager.getFormatInfo(formatId);
if (!formatId)
{
var mimeType = Kekule.Ajax.getResponseMimeType(requestObj);
formatInfo = Kekule.IO.DataFormatsManager.findFormat(mimeType);
}
if (!formatId)
{
var ext = Kekule.UrlUtils.extractFileExt(fileUrl);
formatInfo = Kekule.IO.DataFormatsManager.findFormat(null, ext);
}
if (!formatInfo)
{
var msg = Kekule.$L('ErrorMsg.NO_SUITABLE_READER_FOR_FILEEXT') + ext;
Kekule.raise(msg);
return;
}
var chemObj = Kekule.IO.loadFormatData(data, formatInfo.id, options);
var info = chemObj.getSrcInfo();
info.fileName = fileUrl;
//var success = !!chemObj;
var success = (chemObj !== false);
callback(chemObj, success);
}
else
{
Kekule.raise(Kekule.$L('ErrorMsg.FAIL_TO_LOAD_FILE_URL') + fileUrl);
}
});
}
else
{
Kekule.raise(Kekule.$L('ErrorMsg.AJAX_FILELOADER_NOT_FOUND'));
return null;
}
};
/**
* Save chemObj with certain format.
* @param {String} content
* @param {String} formatId
* @param {Hash} options Additional options to save data. Different data format may have different options.
* @returns {Kekule.ChemObject}
*/
Kekule.IO.saveFormatData = function(chemObj, formatId, options)
{
var writer = Kekule.IO.ChemDataWriterManager.getWriterByFormat(formatId, null, chemObj);
if (writer)
{
var result = writer.writeData(chemObj, null, formatId, options);
return result;
}
else
{
var msg = /*Kekule.ErrorMsg.NO_SUITABLE_WRITER_FOR_FORMAT*/Kekule.$L('ErrorMsg.NO_SUITABLE_WRITER_FOR_FORMAT') + formatId;
Kekule.raise(msg);
return null;
}
};
/**
* Save chemObj to string of mimeType.
* @param {Kekule.ChemObject} chemObj
* @param {String} mimeType
* @param {Hash} options Additional options to save data. Different data format may have different options.
* @returns {String}
*/
Kekule.IO.saveMimeData = function(chemObj, mimeType, options)
{
/*
var writer = Kekule.IO.ChemDataWriterManager.getWriterByMimeType(mimeType);
if (writer)
return writer.writeData(chemObj);
else
{
Kekule.raise(Kekule.ErrorMsg.NO_SUITABLE_WRITER_FOR_MIMETYPE + mimeType);
return null;
}
*/
return Kekule.IO.saveTypedData(chemObj, mimeType, null, options);
};
/**
* Save chem object to a typed content. The type is recognized by mimeType or the file extension.
* @param {Kekule.ChemObj} chemObj
* @param {String} mimeType
* @param {String} urlOrFileExt URL or file ext.
* @param {Hash} options Additional options to save data. Different data format may have different options.
* @returns {Variant}
*/
Kekule.IO.saveTypedData = function(chemObj, mimeType, urlOrFileExt, options)
{
var fileExt;
if (urlOrFileExt)
{
fileExt = Kekule.UrlUtils.extractFileExt(urlOrFileExt);
if (!fileExt)
fileExt = urlOrFileExt;
/*
if (!fileExt)
fileExt = urlOrFileExt;
else
url = urlOrFileExt;
*/
}
var formatId = Kekule.IO.DataFormatsManager.findFormatId(mimeType, mimeType? null: fileExt);
var result;
if (formatId)
result = Kekule.IO.saveFormatData(chemObj, formatId, options);
if (Kekule.ObjUtils.isUnset(result))
{
var msg = mimeType?
(/*Kekule.ErrorMsg.NO_SUITABLE_WRITER_FOR_MIMETYPE*/Kekule.$L('ErrorMsg.NO_SUITABLE_WRITER_FOR_MIMETYPE') + mimeType):
(/*Kekule.ErrorMsg.NO_SUITABLE_WRITER_FOR_FILEEXT*/Kekule.$L('ErrorMsg.NO_SUITABLE_WRITER_FOR_FILEEXT') + fileExt);
Kekule.raise(msg);
return null;
}
else
return result;
/*
var writer;
if (mimeType)
writer = Kekule.IO.ChemDataReaderManager.getWriterByMimeType(mimeType);
else if (urlOrFileExt)
{
var fileExt = Kekule.UrlUtils.extractFileExt(urlOrFileExt);
if (!fileExt)
fileExt = urlOrFileExt;
writer = Kekule.IO.ChemDataReaderManager.getWriterByFileExt(fileExt);
}
if (writer)
return writer.writeData(chemObj);
else
{
var msg = mimeType?
Kekule.ErrorMsg.NO_SUITABLE_WRITER_FOR_MIMETYPE + mimeType:
NO_SUITABLE_WRITER_FOR_FILEEXT + fileExt;
Kekule.raise(msg);
return null;
}
*/
};
})();