/* 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.utils

import org.apache.log4j.Logger

/**
 * @author Shigeru GOUGI
 * @since 0.1
 *        <p/>
 *        Created: February 14, 2008
 */
class ModelUtils {
	private ModelUtils() {}
	
	////
	static log = Logger.getLogger("grails.app.utils.ModelUtils")
	static eventLog = Logger.getLogger("grails.app.utils.ModelEventLog")	

	////////////////////
	static def insertLog(obj) {
		eventLog.debug("beforeInsert: ${obj?.class?.name}")
	}
	static def updateLog(obj) {
		eventLog.debug("beforeUpdate: ${obj?.class?.name}, id = ${obj?.id}")
		if(obj?.id == null)
			log.debug(" dump --->  ${obj}")
	}
	static def deleteLog(obj) {
		eventLog.debug("beforeUpdate: ${obj?.class?.name}, id = ${obj?.id}")
	}
	/////////////////////////////////////////////////////////
	static def cloneCollection(modelCollection) {
		if(modelCollection == null) return []
		return new ArrayList( modelCollection )
	}
	static boolean isEmpty(modelCollection) {
		return modelCollection == null || modelCollection.size() == 0
	}
	/////////////////////////////////////////////////////////
	static boolean containsUsingId (modelCollection, model) {
		if(modelCollection == null || model == null) return false
		for( m in modelCollection ) {
			if( model.class == m.class && model.id == m.id )
				return true
		}
		return false
	}
	/////////////////////////////////////////////////////////
	static delete(modelOrModels) {
		try {		
			if(modelOrModels instanceof Collection) {
				modelOrModels.each() {
					log.debug("delete: ${it.class.name}, id = ${it.id}")
					it.delete()
				}
			} else {
				log.debug("delete: ${modelOrModels.class.name}, id = ${modelOrModels.id}")
				modelOrModels.delete()
			}				
		} catch (e) {
			log.error("delete: ", e)
			return false
		}
		return true
	}
	static deleteWithRollback(modelOrModels,tx) {
		if(delete(modelOrModels)) return true
		tx.setRollbackOnly()
		return false	
	}
	
	static discard(modelOrModels) {
		try {		
			if(modelOrModels instanceof Collection) {
				modelOrModels.each() {
					log.debug("discard: ${it.class.name}, id = ${it.id}")
					it.discard()
				}
			} else {
				log.debug("discard: ${modelOrModels.class.name}, id = ${modelOrModels.id}")
				modelOrModels.discard()
			}				
		} catch (e) {
			log.error("discard: ", e)
			return false
		}
		return true		
	}
	static discardWithRollback(modelOrModels,tx) {
		if(discard(modelOrModels)) return true
		tx.setRollbackOnly()
		return false	
	}

	static validate(modelOrModels) {
		def state = true
		try {		
			if(modelOrModels instanceof Collection) {
				modelOrModels.each() {
					if(!ModelUtils._validateEachWithErrorCheck(it)) {
						state = false
					}
				}
			} else {
				state = _validateEachWithErrorCheck(modelOrModels)
			}				
		} catch (e) {
			log.error("validate: ", e)
			return false
		}
		return true
	}
	static validateWithRollback(modelOrModels,tx) {
		def state = validate(modelOrModels)
		if(!state) {
			log.debug("call tx.setRollbackOnly(): ${modelOrModels.class.name}, id = ${modelOrModels.id}")
			tx.setRollbackOnly()
		}
		return state
	}	

	static save(modelOrModels) {
		def state = true
		try {		
			if(modelOrModels instanceof Collection) {
				modelOrModels.each() {
					if(state)
						state = ModelUtils._saveEachWithErrorCheck(it)
				}
			} else {
				state = _saveEachWithErrorCheck(modelOrModels)
			}				
		} catch (e) {
			log.error("save: ", e)
			return false
		}
		return state
	}
	static saveWithRollback(modelOrModels,tx) {
		def state = save(modelOrModels)
		if(!state){
			log.debug("call tx.setRollbackOnly(): ${modelOrModels.class.name}, id = ${modelOrModels.id}")
			tx.setRollbackOnly()
		}
		return state
	}
	
	static flushWithRollback(modelOrModels,tx) {
		def state = flush(modelOrModels)
		if(!state){
			log.debug("call tx.setRollbackOnly(): ${modelOrModels.class.name}, id = ${modelOrModels.id}")
			tx.setRollbackOnly()
		}
		return state
	}
	static flush(modelOrModels) {
		def state = true
		try {		
			if(modelOrModels instanceof Collection) {
				modelOrModels.each() {
					if(state)
						state = ModelUtils._flushEachWithErrorCheck(it)
				}
			} else {
				state = _flushEachWithErrorCheck(modelOrModels)
			}				
		} catch (e) {
			log.error("flush: ", e)
			return false
		}
		return state		
	}
	
	static printErrors(model) {
	    model.errors?.each {
	          log.error("printErrors: id = ${model.id}:" + it)
	    }		
	}	
	///////////////////////////////////////////////////////////////////
	static private _saveEachWithErrorCheck(model) {
		if(!model) return true
 		if(model.save()) {
 			log.debug("save: ${model.class.name} , id = ${model.id}")
 			return true
 		}else{
			ModelUtils.printErrors(model)
			return false
 		}		
	}
	static private _flushEachWithErrorCheck(model) {
		if(!model) return true
 		if(model.save(flush:true)) {
 			log.debug("flush: ${model.class.name} , id = ${model.id}")
 			return true
 		}else{
			ModelUtils.printErrors(model)
			return false
 		}		
	}	
	static private _validateEachWithErrorCheck(model) {
		assert(model!=null)
 		if (model.validate()) {
 			log.debug("validate: ${model.class.name} , id = ${model.id}")
 			return true
 		}else{
			ModelUtils.printErrors(model)
			return false
 		}
	}	
}

