package com.k_int.aggr2.properties.hdo;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.persistence.Column;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Session;

/**
 * 
 * @author rob
 * 
 * Represents a code which is tied to a particular name space. Uniqueness of the code is enforced 
 * within each name space
 *
 */
@Table(name="CIIM_PROPERTY_NAMESPACED_CODE")
public class NamespacedCodeHDO {

	private String code;
	private NamespaceHDO namespace;
	private long id;
	
	private NamespacedCodeHDO(){
	}
	
	private NamespacedCodeHDO(String code,NamespaceHDO namespace)
	{
		this.code=code;
		this.namespace=namespace;
	}
	
	@Id
	@Column(name="ID")
	@GeneratedValue(strategy=GenerationType.AUTO)
	public Long getId() {
	    return id;
	}
	  
	
	protected void setId(Long id) {
	    this.id = id;
	}
		
	@Column(name="NSPACED_CODE", length=16)
	public String getCode() {
		return code;
	}
	
	
	protected void setCode(String code) {
		this.code = code;
	}
	
	@ManyToOne(fetch=FetchType.EAGER)
	@JoinColumn(name = "NS_FK")
	public NamespaceHDO getNamespace() {
		return namespace;
	}
		
	protected void setNamespace(NamespaceHDO namespace) {
		this.namespace = namespace;
	}
	
	@SuppressWarnings("unchecked")
	public static List<NamespacedCodeHDO> lookupByCode(Session sess, String code) throws PropertyException
	{
		if(code==null)
			throw new NullPointerException("code must not be null");
		try 
		{
		    org.hibernate.Query q = sess.createQuery("Select x from com.k_int.aggr2.properties.hdo.NamespacedCodeHDO x where x.code=?");
		    q.setParameter(0, code, Hibernate.STRING);
		    return (List<NamespacedCodeHDO>)q.list();
		}
		catch (HibernateException he) 
		{
			throw new PropertyException("Failed to look up namespaced code by code: "+code, he);
		}		  
	}
	
	
	public static NamespacedCodeHDO lookupByCodeAndNSUri(Session sess, String code,String ns_uri) throws PropertyException
	{
		if(ns_uri==null || code==null)
			throw new NullPointerException("uri and code must not be null");
		try 
		{
		    org.hibernate.Query q = sess.createQuery("Select x from com.k_int.aggr2.properties.hdo.NamespacedCodeHDO x where x.code=? and x.namespace.uri=");
		    q.setParameter(0, code, Hibernate.STRING);
		    q.setParameter(1, ns_uri, Hibernate.STRING);
		    return (NamespacedCodeHDO) q.uniqueResult();
		}
		catch (HibernateException he) 
		{
			throw new PropertyException("Failed to look up namespaced code by code: "+code+" ns_uri: "+ns_uri, he);
		}		  
	}
	
	public static NamespacedCodeHDO lookupOrCreate(Session sess,String code, String ns_prefix,String ns_uri) throws PropertyException {
		try 
		{
			NamespacedCodeHDO retval = lookupByCodeAndNSUri(sess,code,ns_uri);
			if(retval==null)
			{
				if(ns_uri==null || ns_prefix==null || code==null)
					throw new NullPointerException("Code, NSUri and NSPrefix must not be null");
				else
				{
					Pattern patter = Pattern.compile("([A-Za-z0-9]+)");
					Matcher m = patter.matcher(code);
					if(m.matches()==false)
						throw new PropertyException("Code must only contain alphanumeric characters");
				}
				NamespaceHDO ns = NamespaceHDO.lookupOrCreate(sess, ns_prefix, ns_uri);				
				retval = new NamespacedCodeHDO(code,ns);
				sess.save(retval);
			}
			return retval;
		}
		catch (HibernateException he) 
		{
			throw new PropertyException("Failed to create new namespaced code: "+code+": "+ns_prefix+": "+ns_uri);			    
		}
	}
}
