/*
 * The contents of this file are subject to the Mozilla Public License Version 1.1
 * (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.mozilla.org/MPL/>.
 * 
 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
 * language governing rights and limitations under the License.
 * 
 * The Original Code is the Venice Web Communities System.
 * 
 * The Initial Developer of the Original Code is Eric J. Bowersox <erbo@ricochet.com>,
 * for Silverwrist Design Studios.  Portions created by Eric J. Bowersox are
 * Copyright (C) 2001-2004 Eric J. Bowersox/Silverwrist Design Studios.  All Rights Reserved.
 * 
 * Contributor(s): 
 */
package com.silverwrist.venice.core.impl;

import java.sql.*;
import java.util.*;
import org.apache.log4j.*;
import com.silverwrist.util.*;
import com.silverwrist.venice.core.*;
import com.silverwrist.venice.core.internals.*;
import com.silverwrist.venice.db.*;
import com.silverwrist.venice.except.*;
import com.silverwrist.venice.security.AuditRecord;
import com.silverwrist.venice.security.Role;
import com.silverwrist.venice.svc.GlobalSite;

class AdminOperationsImpl implements AdminOperations
{
  /*--------------------------------------------------------------------------------
   * Internal class for IP ban listings
   *--------------------------------------------------------------------------------
   */

  private static class IPBanInfoImpl implements IPBanInfo
  {
    /*====================================================================
     * Attributes
     *====================================================================
     */

    private int m_id;
    private String m_address;
    private String m_mask;
    private boolean m_enabled;
    private java.util.Date m_expires;
    private String m_message;
    private String m_blocked_by;
    private java.util.Date m_blocked_on;

    /*====================================================================
     * Constructors
     *====================================================================
     */

    IPBanInfoImpl(ResultSet rs) throws SQLException
    {
      m_id = rs.getInt(1);
      m_address = IPv4Util.longToStringAddress(rs.getLong(2));
      m_mask = IPv4Util.longToStringAddress(rs.getLong(3));
      m_enabled = (rs.getInt(4)!=0);
      m_expires = SQLUtil.getFullDateTime(rs,5);
      m_message = rs.getString(6);
      m_blocked_by = rs.getString(7);
      m_blocked_on = SQLUtil.getFullDateTime(rs,8);

    } // end constructor

    IPBanInfoImpl(int id, ResultSet rs) throws SQLException
    {
      m_id = id;
      m_address = IPv4Util.longToStringAddress(rs.getLong(1));
      m_mask = IPv4Util.longToStringAddress(rs.getLong(2));
      m_enabled = (rs.getInt(3)!=0);
      m_expires = SQLUtil.getFullDateTime(rs,4);
      m_message = rs.getString(5);
      m_blocked_by = rs.getString(6);
      m_blocked_on = SQLUtil.getFullDateTime(rs,7);

    } // end constructor

    /*====================================================================
     * Implementations from interface IPBanInfo
     *====================================================================
     */

    public final int getID()
    {
      return m_id;

    } // end getID

    public final String getAddress()
    {
      return m_address;

    } // end getAddress

    public final String getMask()
    {
      return m_mask;

    } // end getMask

    public final boolean isEnabled()
    {
      return m_enabled;

    } // end isEnabled

    public final java.util.Date getExpire()
    {
      return m_expires;

    } // end getExpire

    public final String getMessage()
    {
      return m_message;

    } // end getMessage

    public final String getBlockedBy()
    {
      return m_blocked_by;

    } // end getBlockedBy

    public final java.util.Date getBlockedOn()
    {
      return m_blocked_on;

    } // end getBlockedOn

  } // end class IPBanInfoImpl

  /*--------------------------------------------------------------------------------
   * Static data members
   *--------------------------------------------------------------------------------
   */

  private static Category logger = Category.getInstance(AdminOperationsImpl.class);

  /*--------------------------------------------------------------------------------
   * Attributes
   *--------------------------------------------------------------------------------
   */

  private GlobalSite globalsite;           // global site
  private EnvUser env;                     // the execution environment

  /*--------------------------------------------------------------------------------
   * Constructor
   *--------------------------------------------------------------------------------
   */

  AdminOperationsImpl(GlobalSite globalsite, EnvUser env)
  {
    this.globalsite = globalsite;
    this.env = env;

  } // end constructor

  /*--------------------------------------------------------------------------------
   * Implementations from interface AdminOperations
   *--------------------------------------------------------------------------------
   */

  public SecurityInfo getSecurityInfo()
  {
    VeniceEngine engine = (VeniceEngine)(globalsite.queryService(VeniceEngine.class));
    return engine.getSecurityInfo();

  } // end getSecurityInfo

  public List getAllowedRoleList()
  {
    if (env.testPermission(EnvUser.PERM_DESIGNATEPFY))
      return env.getRoleList("Global.UserLevelsPFY");
    else
      return env.getRoleList("Global.UserLevels");

  } // end getAllowedRoleList

  public List getAuditRecords(int offset, int count) throws DataException
  {
    Connection conn = null;
    List rc = null;

    try
    { // retrieve a connection from the data pool and get the audit records
      conn = globalsite.getConnection(null);
      rc = AuditRecord.getAuditRecords(conn,-1,offset,count);

    } // end try
    catch (SQLException e)
    { // database error - this is a DataException
      logger.error("error loading audit records: " + e.getMessage(),e);
      throw new DataException("unable to load audit records: " + e.getMessage(),e);

    } // end catch
    finally
    { // make sure the connection is released before we go
      SQLUtil.shutdown(conn);

    } // end finally

    return rc;

  } // end getAuditRecords

  public int getAuditRecordCount() throws DataException
  {
    Connection conn = null;
    int rc = -1;

    try
    { // retrieve a connection from the data pool and get the audit records
      conn = globalsite.getConnection(null);
      rc = AuditRecord.getAuditRecordCount(conn,-1);

    } // end try
    catch (SQLException e)
    { // database error - this is a DataException
      logger.error("error loading audit record count: " + e.getMessage(),e);
      throw new DataException("unable to load audit record count: " + e.getMessage(),e);

    } // end catch
    finally
    { // make sure the connection is released before we go
      SQLUtil.shutdown(conn);

    } // end finally

    return rc;

  } // end getAuditRecordCount

  public AdminUserContext getUserContext(int uid) throws DataException
  {
    return AdminUserContextImpl.getAdminUserContext(env,uid);

  } // end getUserContext

  public AdminUserContext getUserContext(String username) throws DataException
  {
    return AdminUserContextImpl.getAdminUserContext(env,username);

  } // end getUserContext

  public CommunityContext getCommunityContext(int cid) throws DataException
  {
    return CommunityUserContextImpl.getCommunityContext(env,cid,true);

  } // end getCommunityContext

  public CommunityContext getCommunityContext(String alias) throws DataException
  {
    return CommunityUserContextImpl.getCommunityContext(env,alias,true);

  } // end getCommunityContext

  public GlobalProperties getProperties()
  {
    return env.getEngine().getProperties();

  } // end getProperties

  public void setProperties(GlobalProperties props) throws DataException
  {
    env.getEngine().setProperties(props);

  } // end setProperties

  public AdminUserContext createNewAccount(String username, String password, boolean prehashed, String reminder,
					   boolean verify_email, boolean lockout, Role base_role,
					   String description, java.sql.Date dob, boolean auto_join)
      throws DataException, AccessError
  {
    if (logger.isDebugEnabled())
      logger.debug("createNewAccount(\"" + username + "\",<password>,<reminder>)...");

    if (base_role==null)
      base_role = env.getDefaultRole("Global.NewUser");

    // Create the user account.
    ReturnNewUser rnu = UserContextImpl.createAccount(env,env.getRemoteAddress(),username,password,prehashed,reminder,
						      verify_email,lockout,0,base_role,description,dob);

    if (auto_join)
    { // Need to create a normal user context here for just a minute to autojoin the communities.
      UserContextImpl rc = new UserContextImpl(globalsite,env);
      rc.loadNewUser("0.0.0.0",rnu.getUserID(),base_role.getLevel(),username,0,rnu.getCreationDate(),
		     rnu.getCreationDate(),dob);
      rc.autoJoinCommunities();

    } // end if

    // Now reload the user context and return it.
    return AdminUserContextImpl.getAdminUserContext(env,rnu.getUserID());

  } // end createNewAccount

  public List getIPBanInfo() throws DataException
  {
    ArrayList rc = null;
    Connection conn = null;
    Statement stmt = null;
    ResultSet rs = null;

    try
    { // retrieve a connection from the data pool and get the audit records
      conn = globalsite.getConnection(null);
      stmt = conn.createStatement();
      rs = stmt.executeQuery("SELECT b.id, b.address, b.mask, b.enable, b.expire, b.message, u.username, b.block_on "
			     + "FROM ipban b, users u WHERE u.uid = b.block_by ORDER BY b.block_on;");
      while (rs.next())
      { // extract the listing of IP blocks
	if (rc==null)
	  rc = new ArrayList();
	rc.add(new IPBanInfoImpl(rs));

      } // end while

    } // end try
    catch (SQLException e)
    { // database error - this is a DataException
      logger.error("error loading IP ban info: " + e.getMessage(),e);
      throw new DataException("unable to load IP ban info: " + e.getMessage(),e);

    } // end catch
    finally
    { // make sure the connection is released before we go
      SQLUtil.shutdown(rs);
      SQLUtil.shutdown(stmt);
      SQLUtil.shutdown(conn);

    } // end finally

    if ((rc==null) || rc.isEmpty())
      return Collections.EMPTY_LIST;
    rc.trimToSize();
    return Collections.unmodifiableList(rc);

  } // end getIPBanInfo

  public IPBanInfo getIPBanInfo(int id) throws DataException
  {
    Connection conn = null;
    PreparedStatement stmt = null;
    ResultSet rs = null;

    try
    { // retrieve a connection from the data pool and get the audit records
      conn = globalsite.getConnection(null);
      stmt = conn.prepareStatement("SELECT b.address, b.mask, b.enable, b.expire, b.message, u.username, b.block_on "
				   + "FROM ipban b, users u WHERE u.uid = b.block_by AND b.id = ?;");
      stmt.setInt(1,id);
      rs = stmt.executeQuery();
      if (rs.next())
	return new IPBanInfoImpl(id,rs);

    } // end try
    catch (SQLException e)
    { // database error - this is a DataException
      logger.error("error loading IP ban info: " + e.getMessage(),e);
      throw new DataException("unable to load IP ban info: " + e.getMessage(),e);

    } // end catch
    finally
    { // make sure the connection is released before we go
      SQLUtil.shutdown(rs);
      SQLUtil.shutdown(stmt);
      SQLUtil.shutdown(conn);

    } // end finally

    return null;

  } // end getIPBanInfo

  public void enableIPBan(int id, boolean enab) throws DataException
  {
    Connection conn = null;
    PreparedStatement stmt = null;

    try
    { // retrieve a connection from the data pool and get the audit records
      conn = globalsite.getConnection(null);
      stmt = conn.prepareStatement("UPDATE ipban SET enable = ? WHERE id = ?;");
      stmt.setInt(1,enab ? 1 : 0);
      stmt.setInt(2,id);
      stmt.executeUpdate();

    } // end try
    catch (SQLException e)
    { // database error - this is a DataException
      logger.error("error setting IP ban info: " + e.getMessage(),e);
      throw new DataException("unable to change IP ban info: " + e.getMessage(),e);

    } // end catch
    finally
    { // make sure the connection is released before we go
      SQLUtil.shutdown(stmt);
      SQLUtil.shutdown(conn);

    } // end finally

  } // end enableIPBan

  public void removeIPBan(int id) throws DataException
  {
    Connection conn = null;
    PreparedStatement stmt = null;

    try
    { // retrieve a connection from the data pool and get the audit records
      conn = globalsite.getConnection(null);
      stmt = conn.prepareStatement("DELETE FROM ipban WHERE id = ?;");
      stmt.setInt(1,id);
      stmt.executeUpdate();

    } // end try
    catch (SQLException e)
    { // database error - this is a DataException
      logger.error("error setting IP ban info: " + e.getMessage(),e);
      throw new DataException("unable to change IP ban info: " + e.getMessage(),e);

    } // end catch
    finally
    { // make sure the connection is released before we go
      SQLUtil.shutdown(stmt);
      SQLUtil.shutdown(conn);

    } // end finally

  } // end removeIPBan

  public void addIPBan(String address, String mask, java.util.Date expires, String message) throws DataException
  {
    Connection conn = null;
    PreparedStatement stmt = null;

    try
    { // retrieve a connection from the data pool and get the audit records
      conn = globalsite.getConnection(null);
      stmt = conn.prepareStatement("INSERT INTO ipban (address, mask, expire, message, block_by, block_on) "
				   + "VALUES (?, ?, ?, ?, ?, ?);");
      try
      { // set the two IP address fields
	stmt.setLong(1,IPv4Util.stringToLongAddress(address));
	stmt.setLong(2,IPv4Util.stringToLongAddress(mask));

      } // end try
      catch (IllegalArgumentException e)
      { // translate to DataException
	throw new DataException(e);

      } // end catch

      SQLUtil.setFullDateTime(stmt,3,expires);
      stmt.setString(4,message);
      stmt.setInt(5,env.getUserID());
      SQLUtil.setFullDateTime(stmt,6,new java.util.Date());
      stmt.executeUpdate();

    } // end try
    catch (SQLException e)
    { // database error - this is a DataException
      logger.error("error setting IP ban info: " + e.getMessage(),e);
      throw new DataException("unable to change IP ban info: " + e.getMessage(),e);

    } // end catch
    finally
    { // make sure the connection is released before we go
      SQLUtil.shutdown(stmt);
      SQLUtil.shutdown(conn);

    } // end finally

  } // end addIPBan

} // end class AdminOperationsImpl
