package org.japanosample;

import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import org.japano.Session;
import org.japano.action.Validator;
import org.japano.util.Util;
import org.japano.metadata.annotation.*;

/**
 Sample implementation of a User class.
 
 This class uses strict synchronisation because it can be accessed
 from multiple sessions in the sample application.
 
 @author  Sven Helmberger ( sven dot helmberger at gmx dot de )
 @version $Id: User.java,v 1.6 2005/02/25 01:27:14 fforw Exp $
 */

public class User implements Serializable
{
  /** The interval in which the user data is resetted in milliseconds.*/  
  public final static int RESET_INTERVAL=60*60*1000;
  
  private static final long serialVersionUID = 0xc04d8ae0f7f10546L;
  
  private final static int FEMALE=1;
  private final static int MALE=2;
  
  /** static List containing all users- */
  public static List USERS;
  static
  {
    reset();
  }

  /**
   Comparator used to sort the list of operating systems alphabetically.
   */
  private static Comparator cmp=new Comparator()
  {
    public int compare(Object a, Object b)
    {
      return ((String)a).compareToIgnoreCase( (String)b);
    }
  };
  
  /** 
   Initial list of operating systems.
   */
  private static List operatingSystems=new ArrayList(Arrays.asList(new String[]
  {
    "Linux",
    "Os-X",
    "Windows"
  } ));

  /** id of the next user instance */
  private static int nextId;
  
  private int id=nextId();  
  private String alias, eMail, password, operatingSystem, bio="";
  private boolean secretEmail=true;
  
  public User()
  {
  }
  
  private synchronized static int nextId()
  {
    return ++nextId;
  }
  
  /**
   Returns the user's id.
   @return id
   */
  public synchronized int getId()
  {
    return id;
  }
  
  /**
   Returns the user's alias.
   @return first name
   */
  public synchronized String getAlias()
  {
    return this.alias;
  }

  /**
   Sets the user's alias.
   @return first name
   */
   ( maxLength=50 )
  public synchronized void setAlias(String alias)
  {
    this.alias=alias;
  }
    
  /**
   * Returns the email address of this user.
   * @return email address
   */
  public synchronized String getEMail()
  {
    return this.eMail;
  }
  
  /**
   The email address of this user.
   @param eMail email address
   */  
   ( regex="[A-Za-z\\.0-9-]+@[A-Za-z\\.0-9-]+", errorMessage="Invalid email address" )
   ( maxLength=256 )
  public synchronized void setEMail(String eMail)
  {
    this.eMail = eMail;
  }
  
  /**
   Returns the SHA1 hash for the password stored.
   @return SHA1 password hash
   */
  public synchronized String getPasswordHash()
  {
    return this.password;
  }
  
  /**
   Stores a new password.
   Internally only a SHA1 hash of the password is stored.
   @param password New password
   */
  public synchronized void setPassword(String password)
  {
    this.password = Util.getSHADigest( password);
  }
  
  /**
   Text area for biography.
   */
   ( maxLength=1024 )
  public synchronized void setBio(String bio)
  {
    this.bio=bio;
  }
  
  /**
   Returns the biography of the user.
   @return biography
   */
  public synchronized String getBio()
  {
    return bio;
  }
  
  /**
   Select for the email secret setting.
   */
   ( options= {
    ( text="Email secret", value="true"),
    ( text="Email public", value="false")
  } )
  public synchronized void setSecretEmail(boolean secretEmail)
  {
    this.secretEmail=secretEmail;
  }
  
  /**
   Returns whether the user's email address is secret or not.
   @return secret?
   */
  public synchronized boolean isSecretEmail()
  {
    return secretEmail;
  }
  
  /**
   The operating system of the user
   */
   ( texts="getAllOperatingSystems" )
  public synchronized void setOperatingSystem(String operatingSystem)
  {
    this.operatingSystem=operatingSystem;
  }
  
  /**
   Returns the operating system of this user.
   @return operating system
   */
  public synchronized String getOperatingSystem()
  {
    return operatingSystem;
  }
  
  private int gender;
  
  /**
   The Gender for this user.
   
   @see #FEMALE
   @see #MALE
   */
   ( options= {
     ( name="female", value="1" ),
     ( name="male", value="2" )
  } )
  public synchronized void setGender(int gender)
  {
    this.gender=gender;
  }
  
  /**
   Returns the gender of the User.
   
   @see #FEMALE
   @see #MALE
   @return gender 
   */
  public synchronized int getGender()
  {
    return gender;
  }
  
  /**
   Returns the user with the given id or <code>null</code>.
   @param id
   @return user instance or <code>null</code>
   */  
  public static User fromId(int id)
  {
    for (Iterator i=USERS.iterator(); i.hasNext(); )
    {
      User u=(User)i.next();
      if (u.getId() == id)
        return u;
    }
    return null;
  }
   
  /**
   Adds a new operating system to the list of operating systems.
   @param system name of the new system.
   */
  public static void addOperatingSystem(String system)
  {
    synchronized (operatingSystems)
    {
      if (!operatingSystems.contains(system))
        operatingSystems.add(system);
      Collections.sort( operatingSystems, cmp);
    }
  }

  
  /**
   Returns the list operating systems.
   @return operating systems.
   */
  public static List getAllOperatingSystems()
  {
    synchronized (operatingSystems)
    {
      return new ArrayList( operatingSystems);
    }
  }
      
  /**
   Returns the EMail address of a given User respecting
   the privacy settings.
   
   An EL function is automatically created for this method.
   
   @param session Session the value will be displayed in.
   @param user User which email address should be returned if allowed.
   */
   ( library="/user" )
  public static String safeEMail(SampleSession session, User user)
  {
    if (user == null)
      return null;
    synchronized (user)
    {
      if (user.isSecretEmail())
      {
        if (!user.equals( session.getUser()))
          return "(EMail secret)";
      }

      return user.getEMail();
    }
  }
  
  private Object readResolve() throws ObjectStreamException
  {
    for (Iterator i=USERS.iterator(); i.hasNext(); )
    {
      User u=(User)i.next();
      if (u.getId() == id)
        return u;
    }
    
    throw new InvalidObjectException("invalid user id");
  } 
  
  private static long lastReset;
              
  public synchronized static void reset()
  {
    List l=new ArrayList();
    User u=new User();
    u.alias="wonko";
    u.setEMail("user@example.com");
    u.setPassword("password");
    u.setGender(MALE);
    l.add(u);
    u=new User();
    u.alias="3jane";
    u.setEMail("user@example.net");
    u.setPassword("password");
    u.setGender(FEMALE);
    l.add(u);
    u=new User();
    u.alias="frodo";
    u.setEMail("user@example.org");
    u.setPassword("password");
    u.setGender(MALE);
    l.add(u);
    
    USERS=Collections.unmodifiableList(l);
    lastReset=System.currentTimeMillis();
  }
  
  public synchronized static long getLastReset()
  {
    return lastReset;    
  }
}