/* ======================================================================
   Parts Copyright 2006 University of Leeds, Oxford University, University of the Highlands and Islands.

   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 org.bodington.messaging;

import java.io.*;
import java.util.Vector;
import java.util.Enumeration;

import org.bodington.server.BuildingServerException;
import org.bodington.sqldatabase.*;
import org.bodington.database.*;
import org.bodington.server.realm.User;
import org.bodington.text.BigString;
import org.bodington.util.VisitationObject;


public class Message 
	extends org.bodington.sqldatabase.SqlPersistentObject 
	implements VisitationObject, Serializable
	{
	public static final int STYLE_PLAINTEXT=0;
	public static final int STYLE_SMARTTEXT=1;
	public static final int STYLE_HTML=2;
	
	public static final int FLAG_SEEN  =1;
	public static final int FLAG_DRAFT =2;
	

	// stored fields are place inside a MessageSummary object
	private MessageSummary summary;
	
	/*
	private PrimaryKey message_id;
	private PrimaryKey messaging_room_id;		//which room does the message belong to
	private PrimaryKey group_id;				//which group (if any) in that room does it belong to
	private PrimaryKey parent_message_id;		//which message is this a follow on/reply to
	private int left_index;						//visitation model left index
	private int right_index;					//visitation model right index
	
	private java.sql.Timestamp created_time;	//time this message was created.
	private java.sql.Timestamp updated_time;	//time message was last edited/new sub message created.
	private PrimaryKey user_id;
	private String author_name;				//name of author at time of posting
	private boolean seen;
	
	private String subject;
	private int style;
	
	private PrimaryKey big_string_id;			// reference to the actual message;
	*/
	
	
	
	
	//protected Vector children_ids;				//stores just the IDs not references to the messages
	
	
	public static Message findMessage( PrimaryKey key )
		throws BuildingServerException
		{
		return (Message)findPersistentObject( key, "org.bodington.messaging.Message" );
		}
	public static Enumeration findMessages( String where )
	    throws BuildingServerException
	    {
	    return findPersistentObjects( where, "org.bodington.messaging.Message" );
	    }
	public static Enumeration findMessages( String where, String order )
	    throws BuildingServerException
	    {
	    return findPersistentObjects( where, order, "org.bodington.messaging.Message" );
	    }
	
	
	public Message()
		{
		summary = new MessageSummary();
		}
	
	
	// dummy save method put in for development work
	//static int xxx = 0;
	//public void save()
	//	{
	//	summary.setMessageId( new PrimaryKey( xxx++ ) );
	//	}

	
	
	
    public PrimaryKey getPrimaryKey()
		{
        return getMessageId();
        }

    public void setPrimaryKey(PrimaryKey key)
    	{
    	setMessageId( key );
    	}
    	
    public PrimaryKey getMessageId()
		{
        return summary.getMessageId();
        }

    public void setMessageId(PrimaryKey key)
    	{
    	summary.setMessageId( key );
    	setUnsaved();
    	}
    	

    public PrimaryKey getMessagingRoomId()
		{
        return summary.getMessagingRoomId();
        }

    public void setMessagingRoomId(PrimaryKey key)
    	{
    	summary.setMessagingRoomId( key );
    	setUnsaved();
    	}
    	

    
    public PrimaryKey getGroupId()
		{
        return summary.getGroupId();
        }

    public void setGroupId(PrimaryKey key)
    	{
    	summary.setGroupId( key );
    	setUnsaved();
    	}
    	

    
    public PrimaryKey getParentMessageId()
		{
        return summary.getParentMessageId();
        }

    public void setParentMessageId(PrimaryKey key)
    	{
    	summary.setParentMessageId( key );
    	setUnsaved();
    	}
    	

    public PrimaryKey getReplyToMessageId()
		{
        return summary.getReplyToMessageId();
        }

    public void setReplyToMessageId(PrimaryKey key)
    	{
    	summary.setReplyToMessageId( key );
    	setUnsaved();
    	}
    	

   	public int getLeftIndex()
		{
		return summary.getLeftIndex();
		}
	public void setLeftIndex( int l )
		{
		if ( l==summary.getLeftIndex() ) return;
		summary.setLeftIndex( l );
    	setUnsaved();
		}

	public int getRightIndex()
		{
		return summary.getRightIndex();
		}
	public void setRightIndex( int r )
		{
		if ( r==summary.getRightIndex() ) return;
		summary.setRightIndex( r );
    	setUnsaved();
		}


    /**
     * Gets the time this message was last edited.
     * @return Timestamp when message was last edited.
     */
    public java.sql.Timestamp getEditedTime()
        {
        return summary.getEditedTime();
        }

    /**
     * Sets the time this message was last edited.
     * @param t Timestamp when message was last edited.
     */
    public void setEditedTime( java.sql.Timestamp t )
        {
        summary.setEditedTime( t );
        setUnsaved();
        }


	public java.sql.Timestamp getCreatedTime()
		{
		return summary.getCreatedTime();
		}
	public void setCreatedTime( java.sql.Timestamp t )
		{
		summary.setCreatedTime( t );
        setUnsaved();
		}


	public java.sql.Timestamp getUpdatedTime()
		{
		return summary.getUpdatedTime();
		}
	public void setUpdatedTime( java.sql.Timestamp t )
		{
		summary.setUpdatedTime( t );
        setUnsaved();
		}


    public void setUserId( PrimaryKey key )
	    {
	    summary.setUserId( key );
	    setUnsaved();
	    }
    public PrimaryKey getUserId()
	    {
        return summary.getUserId();
	    }
	public void setUser( User u )
		{
		setUserId( u.getUserId() );
		}
	public User getUser()
		throws BuildingServerException
		{
		return User.findUser( summary.getUserId() );
		}
		
    /**
     * Sets the name of author at time of edit.
     * @param name of author at time of edit.
     */
    public void setEditorName( String name )
        {
        summary.setEditorName( name );
        setUnsaved();
        }

    /**
     * Gets the name of author at time of edit.
     * @return name of author at time of edit.
     */
    public String getEditorName()
        {
        return summary.getEditorName();
        }

    public void setAuthorName( String n )
	    {
	    summary.setAuthorName( n );
	    setUnsaved();
	    }

    public String getAuthorName()
	    {
        return summary.getAuthorName();
	    }


	public int getFlags()
		{
		int f=0;
		if ( beenSeen() )
			f = f | FLAG_SEEN;
		if ( isDraft() )
			f = f | FLAG_DRAFT;
		return f;
		}
	public void setFlags( int f )
		{
		setSeen(  (f & FLAG_SEEN )!=0 );
		setDraft( (f & FLAG_DRAFT)!=0 );
		}
	public boolean beenSeen()
		{
		return summary.beenSeen();
		}
	public void setSeen( boolean b )
		{
		if ( b==summary.beenSeen() ) return;
		summary.setSeen( b );
    	setUnsaved();
		}
	public boolean isDraft()
		{
		return summary.isDraft();
		}
	public void setDraft( boolean b )
		{
		if ( b==summary.isDraft() ) return;
		summary.setDraft( b );
    	setUnsaved();
		}

    
    public void setSubject( String n )
	    {
	    summary.setSubject( n );
	    setUnsaved();
	    }

    public String getSubject()
	    {
        return summary.getSubject();
	    }


	public int getStyle()
		{
		return summary.getStyle();
		}
	public void setStyle( int r )
		{
		if ( r==summary.getStyle() ) return;
		summary.setStyle( r );
    	setUnsaved();
		}


    
    public void setBigStringId( PrimaryKey key )
	    {
	    summary.setBigStringId( key );
	    setUnsaved();
	    }
    public PrimaryKey getBigStringId()
	    {
        return summary.getBigStringId();
	    }



	public String getString()
		throws BuildingServerException
		{
		PrimaryKey big_string_id = summary.getBigStringId();
		if ( big_string_id == null )
			return null;
		BigString big = BigString.findBigString( big_string_id );
		if ( big == null )
			return null;
		return big.getString();
		}


	public String getMessageText( String mime_type )
		throws BuildingServerException
		{
		return getMessageText( this.getSummary(), mime_type );
		}

	public static String getMessageText( MessageSummary summary, String mime_type )
		throws BuildingServerException
		{
                    return getMessageText( summary ,mime_type, 0 );
                }
        
	public static String getMessageTextSample( MessageSummary summary, int max_length )
		throws BuildingServerException
		{
                    return getMessageText( summary, "text/plain", max_length );
                }
        
	private static String getMessageText( MessageSummary summary, String mime_type, int max_length )
		throws BuildingServerException
		{
		char c, last_out;
		int i, j;
		StringBuffer buffer=null;
		
		PrimaryKey big_string_id = summary.getBigStringId();
		if ( big_string_id == null )
			return null;
		BigString big = BigString.findBigString( big_string_id );
		if ( big == null )
			return null;

		String preprocessed = big.getString();
		
		if ( mime_type == null )
			return preprocessed;
		
		if ( mime_type.equals( "text/html" ) )
			{		
			if ( summary.getStyle() == STYLE_HTML )
				return preprocessed;
				
			if (	summary.getStyle() == STYLE_PLAINTEXT || 
		    		summary.getStyle() == STYLE_SMARTTEXT	)
				{
				buffer = new StringBuffer( preprocessed.length() + preprocessed.length()/10 );
				
				buffer.append( "<P><TT>" );
				for ( i=0; i< preprocessed.length(); i++ )
					{
					if ( summary.getStyle() == Message.STYLE_SMARTTEXT )
						{
						if ( preprocessed.regionMatches( i, "http:",   0, 5 ) ||
						    	preprocessed.regionMatches( i, "ftp:",    0, 4 ) ||
						    	preprocessed.regionMatches( i, "mailto:", 0, 7 ) )
							{
							buffer.append( "<A TARGET=_new HREF=\"" );
							for ( j=i; j<preprocessed.length(); j++ )
								{
								c=preprocessed.charAt( j );
								if ( Character.isWhitespace( c ) )
									break;
								buffer.append( preprocessed.charAt( j ) );
								}
							buffer.append( "\">" );
							for ( j=i; j<preprocessed.length(); j++ )
								{
								c=preprocessed.charAt( j );
								if ( Character.isWhitespace( c ) )
									break;
								buffer.append( preprocessed.charAt( j ) );
								}
							buffer.append( "</A>" );
							i=j;
							}
						}
					if ( i>=preprocessed.length() )
						break;

					c = preprocessed.charAt( i );
					switch ( c )
						{
						case '"':
							buffer.append( "&quot;" );
							break;
						case '&':
							buffer.append( "&amp;" );
							break;
						case '<':
							buffer.append( "&lt;" );
							break;
						case '>':
							buffer.append( "&gt;" );
							break;
						case '\n':
							buffer.append( "</TT></P>\n<P><TT>" );
							break;
						default:
							buffer.append( c );
						}
					}
				buffer.append( "</TT></P>" );
				return buffer.toString();
				}
			}
			
		// all other mime types.
		if ( summary.getStyle() == STYLE_HTML )
			{
			// remove the tags.
			boolean intag=false, inwhite=false;
			buffer = new StringBuffer( preprocessed.length() + preprocessed.length()/10 );
			last_out=' ';
			for ( i=0; i< preprocessed.length(); i++ )
				{
				if ( preprocessed.regionMatches( i, "<P>",   0, 3 ) ||
				     preprocessed.regionMatches( i, "<p>",   0, 3 )   )
					{
					if ( last_out!='\n' )
						{
						last_out='\n';
						buffer.append( "\n\n" );
						}
					i+=2;
					intag=false;
					continue;
					}
				if ( preprocessed.regionMatches( i, "</P>",   0, 4 ) ||
				     preprocessed.regionMatches( i, "</p>",   0, 4 )    )
					{
					if ( last_out!='\n' )
						{
						last_out='\n';
						buffer.append( "\n\n" );
						}
					i+=3;
					intag=false;
					continue;
					}
				if ( preprocessed.regionMatches( i, "<BR>",   0, 4 ) ||
				     preprocessed.regionMatches( i, "<br>",   0, 4 ) 	)
					{
					if ( last_out!='\n' )
						{
						last_out='\n';
						buffer.append( last_out );
						}
					i+=3;
					intag=false;
					continue;
					}
				
				
				c = preprocessed.charAt( i );
					
				if ( c == '<' )
					intag=true;
				if ( c == '>' )
					{
					intag=false;
					continue;
					}
					
				if ( intag )
					continue;
					
				if ( Character.isWhitespace( c ) )
					{
					// don't output more whitespace
					if ( inwhite )
						continue;
					inwhite=true;
					//output one space for first whitespace
					buffer.append( ' ' );
					last_out = ' ';
					}
				else
					{
					inwhite = false;
					buffer.append( c );
					last_out = c;
					}
				}
				
			// return buffer.toString();
			}
                else
                {
			buffer = new StringBuffer( preprocessed.length() + preprocessed.length()/10 );
                        buffer.append( preprocessed.toString() );
                }
			
                // if a maximum length was specified (plain text only)
                if ( max_length>0 && buffer.length()>max_length )
                {
                    // crop to max length
                    buffer.setLength( max_length );
                    // nibble some off to space between words but give up if can't find space
                    // after 20 chars
                    for ( i=0; Character.isWhitespace( buffer.charAt( buffer.length()-1 ) ) && i<20; i++ )
                        buffer.setLength( buffer.length() -1 );
                }
                
		return buffer.toString();
		}

	public MessageSummary getSummary()
		{
		return summary;
		}

	}
