/* ======================================================================
   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.server.realm;

import org.bodington.server.resources.*;
import org.bodington.server.*;
import org.bodington.sqldatabase.*;
import org.bodington.database.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.util.Vector;


/**
 * Represents properties and code for editing sets of aliases.
 * 
 * @author Jon Maber
 * @version 1.0
 */
public class AliasEditor extends org.bodington.server.resources.Resource
	{

	// return a class that will 'front end' the resource
	// for a user.
	public Class sessionClass()
		{
		return UserManagementSessionImpl.class;
		}


    
	private void checkAliasParameters( PrimaryKey aliasid, String s, boolean is_primary, String user_cat )
		throws BuildingServerException
	    {
	    int i;
		Alias alias, oldalias=null;
	    StringBuffer where = new StringBuffer( 64 );
	    
	    if ( !this.checkPermission( Permission.EDIT ) )
			throw new BuildingServerException( "You don't have 'edit' level access to this resource." );

		if ( aliasid!=null )
			{
			oldalias = Alias.findAlias( aliasid );
			if ( oldalias==null )
				throw new BuildingServerException( "The specified alias wasn't found." );
			Zone edit_zone = getEffectiveZone();
			Zone alias_zone = oldalias.getZone();
			if ( !edit_zone.equals( alias_zone ) )
				throw new BuildingServerException( "The specified alias can't be edited because it belongs to a different administrative zone." );
			}

	    if ( s==null )
			throw new BuildingServerException( "No name was specified for the new unique identifier." );
	    
	    s=s.trim();
	    if ( s.length()>64 )
			throw new BuildingServerException( "The specified name is too long (>64 characters)." );
	    if ( s.length()<1 )
			throw new BuildingServerException( "The specified name is too short (<1 character)." );
	    
	    char c;
	    for ( i=0; i<s.length(); i++ )
			{
			c=s.charAt(i);
			if ( !Character.isLetterOrDigit( c ) &&   c != '_'  &&  c != '-' &&  c != '.')
				throw new BuildingServerException( "The specified name can only contain letters digits, '-',  '_' or '.'." );
			}
			
		if ( oldalias != null )
			{
			where.append( "alias_id <> " );
			where.append( aliasid.toString() );
			where.append( " AND " );
			}
		where.append( "zone_id = " );
		where.append( getEffectiveZoneId().toString() );
		where.append( " AND alias_name = '" );
		where.append( s );
		where.append( "'" );
		alias = Alias.findAlias( where.toString() );
		if ( alias!=null )
			throw new BuildingServerException( "Another unique identifier already exists with the name that was given - you can't have two the same." );

		if ( is_primary )
			{
		    if ( user_cat==null )
				throw new BuildingServerException( "A user category list must be specified for the new primary unique identifier." );
	    	user_cat=user_cat.trim();
	    	if ( user_cat.length()>64 )
				throw new BuildingServerException( "The specified user category list is too long (>64 characters)." );
	    	if ( user_cat.length()<1 )
				throw new BuildingServerException( "The specified user category list is too short (<1 character)." );
				
			StringTokenizer tok = new StringTokenizer( user_cat, "," );
			if ( tok.countTokens()<1 )
				throw new BuildingServerException( "The specified user category list contains no entries." );
				
			String t;
			while ( tok.hasMoreTokens() )
				{
				t = tok.nextToken();
		    	if ( t.length()<1 )
					throw new BuildingServerException( "The specified user category is too short (<1 character)." );
	    		for ( i=0; i<t.length(); i++ )
					{
					c=t.charAt(i);
					if ( !Character.isLetterOrDigit( c ) &&   c != '_'  &&  c != '-' &&  c != '.')
						throw new BuildingServerException( "The user category can only contain letters digits, '-',  '_' or '.'." );
					}
				}
			
			/*
			where.setLength( 0 );
			if ( oldalias != null )
				{
				where.append( "alias_id <> " );
				where.append( aliasid.toString() );
				where.append( " AND " );
				}
			where.append( "zone_id = " );
			where.append( getEffectiveZoneId().toString() );
			where.append( " AND user_category = '" );
			where.append( user_cat );
			where.append( "'" );
			alias = Alias.findAlias( where.toString() );
			if ( alias!=null )
				throw new BuildingServerException( "Another  unique identifier already exists with the user category that was given - you can't have two the same." );
			*/
			}


		}


	public void createAlias( String s, boolean is_primary, String user_cat )
		throws BuildingServerException
	    {
	    Alias alias;
	    
	    checkAliasParameters( null, s, is_primary, user_cat );

		alias = new Alias();
		alias.setZoneId( getEffectiveZoneId() );
		alias.setAliasName( s );
		alias.setAliasType( is_primary?new Integer( Alias.TYPE_PRIMARY ):new Integer( Alias.TYPE_SECONDARY ) );	
		alias.setUserCategory( is_primary?user_cat.trim():null );
		alias.save();
	    }
	    

	public void editAlias( PrimaryKey aliasid, String s, boolean is_primary, String user_cat )
		throws BuildingServerException
	    {
	    Alias alias;
	    checkAliasParameters( aliasid, s, is_primary, user_cat );
	    
		alias = Alias.findAlias( aliasid );
		if ( alias==null )
			throw new BuildingServerException( "The specified alias wasn't found." );
		alias.setZoneId( getEffectiveZoneId() );
		alias.setAliasName( s.trim() );
		alias.setAliasType( is_primary?new Integer( Alias.TYPE_PRIMARY ):new Integer( Alias.TYPE_SECONDARY ) );	
		alias.setUserCategory( is_primary?user_cat.trim():null );
		alias.save();
	    }
	    

	public void createAliasEntries( String alias_name, BufferedReader reader )
		throws BuildingServerException
	    {
	    Vector entry_list=new Vector();
		Alias alias;
	    
	    if ( !this.checkPermission( Permission.EDIT ) )
			throw new BuildingServerException( "You don't have 'edit' level access to this resource." );

	    String s=alias_name.trim();
		alias = Alias.findAlias(alias_name, getEffectiveZone());
		if ( alias==null )
			throw new BuildingServerException( "The specified unique identifier doesn't exist within the adminsitrative zone." );

		String line, value;
		AliasEntry entry;
		StringTokenizer tok;
		int id, i;
	    char c;
		try
			{
			line = reader.readLine();
			while ( line!=null )
				{
				tok=new StringTokenizer( line, "\t" );
				if ( tok.countTokens()==0 )
					continue;
				if ( tok.countTokens()!=2 )
					throw new BuildingServerException( "Invalid input - two columns delimited by TABS expected." );
				try
					{
					id = Integer.parseInt( tok.nextToken() );
					}
				catch ( NumberFormatException numex )
					{
					throw new BuildingServerException( "Invalid input - first column should contain bodington system ID numbers." );
					}

				value=tok.nextToken();
	    		for ( i=0; i<value.length(); i++ )
					{
					c=value.charAt(i);
					if ( !Character.isLetterOrDigit( c ) &&   c != '_'  &&  c != '-' &&  c != '.' )
						throw new BuildingServerException( "Values in column two can only contain letters digits, '-' or '_' or '.'." );
					}

				entry = new AliasEntry();
				entry.setAlias( alias );
				entry.setUserId( new PrimaryKey( id ) );
				entry.setUserAlias( value );
				//don't save entries until they are all parsed in without error
				entry_list.addElement( entry );
				
				line = reader.readLine();
				}
			}
		catch ( IOException ioex )
			{
			throw new BuildingServerException( "IO Error reading input.\n" + ioex );
			}
		
		for ( int j=0; j< entry_list.size(); j++ )
			{
			entry = (AliasEntry)entry_list.elementAt( j );
			entry.save();
			}
		
		return;
		}



	public Enumeration findEditableAliases()
		throws BuildingServerException
		{
		PrimaryKey zid = getEffectiveZoneId();
		if ( zid == null )
			throw new BuildingServerException( "This tool is not within a defined administrative zone." );
		return Alias.findAliases( "zone_id = " + zid.toString() );
		}

	public String getPrefix()
		throws BuildingServerException
		{
		StringBuffer name = new StringBuffer();
		boolean in_groups;
		Resource current;
		Enumeration ancestors = this.findAncestors();
		
		in_groups=false;
		while ( ancestors.hasMoreElements() )
			{
			current = (Resource)ancestors.nextElement();
			if ( in_groups )
				{
				if ( this.getHttpFacilityNo() != current.getHttpFacilityNo() )
					{
					in_groups=false;
					name.setLength( 0 );
					continue;
					}
				name.append( current.getName() );
				name.append( "." );
				}
			else
				{
				if ( this.getHttpFacilityNo() == current.getHttpFacilityNo() )
					{
					in_groups=true;
					name.setLength( 0 );
					name.append( current.getName() );
					name.append( "." );
					}
				}
			}

		if ( name.length() == 0 )
			return null;
			
		return name.toString();
		}

	}
