@Entity
@Name("hl7Message")
@Table(name = "pxy_hl7_message", schema = "public" )
@SequenceGenerator(name = "pxy_hl7_message_sequence", sequenceName = "pxy_hl7_message_id_seq", allocationSize=1)
public class HL7Message implements java.io.Serializable {


	/** Serial ID version of this object */
	private static final long serialVersionUID = 5415340912398088L;
	
	private static org.apache.log4j.Logger log= org.apache.log4j.Logger.getLogger(HL7Message.class) ;
	//	Attributes (existing in database as a column)
	@Id
	@Column(name = "id", unique = true, nullable = false)
	@NotNull
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="pxy_hl7_message_sequence")
    private Integer id;
	
	@Temporal(TemporalType.TIMESTAMP)
	@Column(name = "date_received" )
    private Date dateReceived ;
	
	
	@Column( name="from_ip" )
    private String fromIP ;
	

	@Column( name="proxy_port" )
    private String proxyPort ;
	
	@Column( name="to_ip" )
    private String toIP ;
	
	@Column( name="remote_port" )
    private String remotePort ;
	
	
	@Column( name="messageReceived" )
	@Lob
    private String messageReceived ;
	
	  
	
	
	//	Constructors
	 

	public Integer getId() {
		return id;
	}


	public void setId(Integer id) {
		this.id = id;
	}


	public Date getDateReceived() {
		return dateReceived;
	}


	public void setDateReceived(Date dateReceived) {
		this.dateReceived = dateReceived;
	}


	public String getFromIP() {
		return fromIP;
	}


	public void setFromIP(String fromIP) {
		this.fromIP = fromIP;
	}


	public String getToIP() {
		return toIP;
	}


	public void setToIP(String toIP) {
		this.toIP = toIP;
	}


	public String getMessageReceived() {
	
		return  messageReceived ;
	}

	public void setMessageReceived(String inMessageReceived) 
	{
		this.messageReceived  = inMessageReceived ;
	    
	}
	
	public String getProxyPort() {
		return proxyPort;
	}


	public void setProxyPort(String inProxyPort) {
		this.proxyPort = inProxyPort;
	}


	public String getRemotePort() {
		return remotePort;
	}


	public void setRemotePort(String remotePort ) {
		this.remotePort = remotePort;
	}


	public HL7Message()
	{
		
	}


	 

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((dateReceived == null) ? 0 : dateReceived.hashCode());
		result = prime * result
				+ ((remotePort == null) ? 0 : remotePort.hashCode());
		result = prime * result + ((fromIP == null) ? 0 : fromIP.hashCode());
		result = prime * result
				+ ((proxyPort == null) ? 0 : proxyPort.hashCode());
		result = prime * result
				+ ((messageReceived == null) ? 0 : messageReceived.hashCode());
		result = prime * result + ((toIP == null) ? 0 : toIP.hashCode());
		return result;
	}


	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		HL7Message other = (HL7Message) obj;
		if (dateReceived == null) {
			if (other.dateReceived != null)
				return false;
		} else if (!dateReceived.equals(other.dateReceived))
			return false;
		if (remotePort == null) {
			if (other.remotePort != null)
				return false;
		} else if (!remotePort.equals(other.remotePort))
			return false;
		if (fromIP == null) {
			if (other.fromIP != null)
				return false;
		} else if (!fromIP.equals(other.fromIP))
			return false;
		if (proxyPort == null) {
			if (other.proxyPort != null)
				return false;
		} else if (!proxyPort.equals(other.proxyPort))
			return false;
		if (messageReceived == null) {
			if (other.messageReceived != null)
				return false;
		} else if (!messageReceived.equals(other.messageReceived))
			return false;
		if (toIP == null) {
			if (other.toIP != null)
				return false;
		} else if (!toIP.equals(other.toIP))
			return false;
		return true;
	}


	public String getMessageReceivedWrapped()
	{
		if ( messageReceived == null ) return "" ;
		String sToUse = new String(Base64.decode(messageReceived)).trim() ;
		
		return   WordUtils.wrap (sToUse.substring(0, (sToUse.length() > 200 ? 200 : sToUse.length())) , 60 ) +"..."   ;
	}
	 
	   
	public HL7Message(String fromIP, Integer localPort , String toIP, Integer remotePort , String messageReceived) {
		super();
		this.dateReceived = new Date() ;
		this.fromIP = fromIP;
		this.toIP = toIP;
		this.proxyPort = localPort.toString() ;
		this.remotePort = remotePort.toString() ;
		
		setMessageReceived(  messageReceived  );
	}


	 
	public static HL7Message writeMessage ( EntityManager em , HL7Message hl7Message )
	{
		if ( em == null || hl7Message == null ) 
			{
			log.fatal("entityManager null or HL7Message null") ;
			  return null ;
			} 
		HL7Message messageToReturn = null ;
	
				boolean transactionWasActive = false ;
					
				EntityTransaction transaction =  em.getTransaction() ;
				synchronized (transaction) 
				{
					if ( !transaction.isActive() )
					{
						transaction.begin() ;
						
					}
					else transactionWasActive = true ;
					 
					hl7Message.setMessageReceived(Base64.encodeBytes(hl7Message.getMessageReceived().getBytes())) ;
					messageToReturn = em.merge(hl7Message) ;
					 
					 
			        if ( !transactionWasActive )
			        {
			        	transaction.commit() ;
			        }
	         	} 
		
		return messageToReturn ;
	}

	public static HL7Message writeMessage ( EntityManager em , HL7Message hl7Message , Channel inChannelUsed )
	{
		if ( em == null || hl7Message == null ) 
			{
			log.fatal("entityManager null or HL7Message null") ;
			  return null ;
			} 
		HL7Message messageToReturn = null ;
	
				boolean transactionWasActive = false ;
					
				EntityTransaction transaction =  em.getTransaction() ;
				synchronized (transaction) 
				{
					if ( !transaction.isActive() )
					{
						transaction.begin() ;
						
					}
					else transactionWasActive = true ;
					 
					hl7Message.setMessageReceived(Base64.encodeBytes(hl7Message.getMessageReceived().getBytes())) ;
					messageToReturn = em.merge(hl7Message) ;
					 
					 if ( inChannelUsed != null )
					 {
						 inChannelUsed = em.find(Channel.class, inChannelUsed.getId() ) ;
						// log.info("getNumberOfMessageReceived : " + inChannelUsed.getNumberOfMessageReceived() ) ;
						 inChannelUsed.setNumberOfMessageReceived( inChannelUsed.getNumberOfMessageReceived().add( new BigInteger("1" ) )) ;
						 inChannelUsed.setLastMessageDate(new Date() ) ;
						 inChannelUsed = em.merge( inChannelUsed ) ;
					 }
					  
			        if ( !transactionWasActive )
			        {
			        	transaction.commit() ;
			        }
	         	} 
		
		return messageToReturn ;
	}

	/**
	 * If date2 is null we will search at exact date1
	 * @param em
	 * @param hl7Message
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static List getMessagesBetweenDates ( EntityManager em ,  Date date1 , Date date2 )
	{
		if ( em == null  || (date1 == null && date2 == null ) )
			{
			log.fatal("entityManager null and date1, date2 are null") ;
			  return null ;
			} 
	 
		Query q = null ;
		if ( date1 ==null )
			{
			  date1 = date2 ;
			    q = em.createQuery("SELECT message from HL7Message message where message.dateReceived = :date1") ;
				q.setParameter("date1", date1 ) ;
			}
		else
		{
		
		 q = em.createQuery("SELECT message from HL7Message message where  message.dateReceived > :date1 and  message.dateReceived< :date2") ;
		 q.setParameter("date1", date1 ) ;
		 q.setParameter("date2", date2 ) ;
		}
		
		if ( q == null ) return null ;
		
		return q.getResultList() ;
	}

	@SuppressWarnings("unchecked")
	public static List getAllMessages( EntityManager em, Integer nbMessages )
	{
	  if ( em == null ) return null ;
	  
	  if ( nbMessages < 0 ) return null ;
	  
	  Query q = em.createQuery("SELECT message from HL7Message message order by message.id desc ") ;
	  if ( nbMessages > 0 )
	  {
		  q.setMaxResults( nbMessages ) ;
	  }
	  
	  return q.getResultList() ;
	}
	
	/**
	 * If date2 is null we will search at exact date1
	 * @param em
	 * @param hl7Message
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static List getMessagesBetweenDates ( EntityManager em ,  Date date1 , Date date2 , String from , String to )
	{ 
		//TODO : Write this method 
		return null ;
	}
	
}