/* Copyright 2008 we-lab-doc! (http://www.we-lab-doc.com/)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.we_lab_doc.spacecard.model.abstracts

import net.sf.json.*
import com.we_lab_doc.spacecard.model.*
import com.we_lab_doc.spacecard.utils.*
import com.we_lab_doc.spacecard.model.exception.ForwardingException

/**
 * @author Shigeru GOUGI
 * @since 0.1
 *        <p/>
 *        Created: March 19, 2008
 *
 */
abstract class DataTray implements SpaceCardDomainModel {
	boolean remove() {
		return ModelUtils.delete(this)
	}
	void put(Object obj) {
		assert obj != null
		try {
			String stringObj
			if( obj instanceof JSONObject ) {
				type = JSONObjectTYPE
				objClass = JSONObject.class.name
				stringObj = obj.toString()
			} else if( obj instanceof JSONArray ) {
				type = JSONArrayTYPE
				objClass = JSONArray.class.name			
				stringObj = obj.toString()
			} else if(obj instanceof List ) {
				List aList = (List)obj
				if(aList.size() > 0) {
					objClass = aList.get(0).class.name
				} else {
					objClass = Object.class.name
				}
				type = ListTYPE
				stringObj = JSONArray.fromObject( obj ).toString()			
			} else if(obj instanceof Collection ) {
				Collection aCol = (Collection)obj
				if(aCol.size() > 0) {
					objClass = aCol.iterator().next().class.name
				} else {
					objClass = Object.class.name
				}
				type = CollectionTYPE
				stringObj = JSONArray.fromObject( obj ).toString()
			} else if(obj instanceof Object[]) {
				Object [] objAry = (Object[])obj
				if(objAry.length > 0) {
					objClass = objAry[0].class.name
				} else {
					objClass = Object.class.name
				}
				type = ArrayTYPE
				stringObj = JSONArray.fromObject( obj ).toString()
			} else if(obj instanceof String || obj instanceof GString ) {
				type = StringTYPE
				objClass = String.class.name
				stringObj = obj.toString()
			} else {
				type = BeanTYPE
				objClass = obj.class.name
				stringObj = JSONObject.fromObject( obj ).toString()
			}
			stringBytes = stringObj.getBytes("utf8")
		} catch(e) {
			throw new ForwardingException("DataTray#putObject() failed", e)	
		}
	}
	Object get() {
		if(!stringBytes) return null
		try {
			def stringObj = new String(stringBytes, "utf8")			
			switch (type) {
			case JSONObjectTYPE:
				return JSONObject.fromObject(stringObj)
			case JSONArrayTYPE:
				return JSONArray.fromObject(stringObj)
			case BeanTYPE:
				return JSONObject.toBean(JSONObject.fromObject(stringObj) , Class.forName(objClass))
			case CollectionTYPE:
				return JSONArray.toCollection(JSONArray.fromObject(stringObj), Class.forName(objClass))
			case ListTYPE:
				return JSONArray.toList(JSONArray.fromObject(stringObj), Class.forName(objClass))
			case ArrayTYPE:
				return JSONArray.toCollection(JSONArray.fromObject(stringObj), Class.forName(objClass)).toArray()
			case StringType:
				return stringObj
			default:
				throw new IllegalStateException("DataTray#getObject(); unexpected type: type = ${type} ")				
			}
		} catch(e) {
			throw new ForwardingException("DataTray#getObject() failed", e)
		}
	}
	/////////////////////////////////////////////
	def beforeInsert = {
		ModelUtils.insertLog(this)
		onBeforeInsert(delegate)
	}
	def beforeUpdate = {
		ModelUtils.updateLog(this)
		onBeforeUpdate(delegate)
	}
	def beforeDelete = {
		ModelUtils.deleteLog(this)
		onBeforeDelete(delegate)
	}
	/////////////////////////////////////////////
	protected onBeforeInsert(obj) {
		obj.createdDate = new Date()
	}
	protected onBeforeUpdate(obj) {
		obj.updatedDate = new Date()		
	}
	protected onBeforeDelete(obj) {
		/* don't delete*/		
	}		
	/////////////////////////////////////////////
	static transients  = ['object']	
	static constraints = {
		key(unique:true)		
		stringBytes(nullable:false)
		type(blank:false)
		objClass(blank:false)
		///
		expirationDate(nullable:true)
		updatedDate(nullable:true)
		createdDate(nullable:true)		
		moduleName(nullable:true)
		dataFormatVersion(nullable:false)
		dataName(blank:false)
	}
	/////////////////////////////////////////////
	Date expirationDate
	Date updatedDate
	Date createdDate	
	String moduleName // 名前がいまいち
	String dataFormatVersion
	String dataName
	////
	String key
	String type
	String objClass		
	byte[] stringBytes	
	/////////////////////////////////////////////
	final static def JSONObjectTYPE = "JSONObject"
	final static def JSONArrayTYPE  = "JSONArray"
	final static def CollectionTYPE = "Collection"
	final static def ListTYPE       = "List"
	final static def ArrayTYPE      = "Array"
	final static def BeanTYPE       = "Bean"
	final static def StringTYPE     = "String"	
}