import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;

/**
 * The BulletinBoard servlet allows the user to view posted
 * bulletins as well as add their own bulletins to be viewed by
 * others.
 *
 * @author Dustin R. Callaway
 * @version 1.0, 04/29/98
 */
public class BulletinBoard extends HttpServlet
{
  //class variables
  static String filePath; //stores root path for bulletins files

  /**
   * init method is called when servlet is first loaded. It
   * reads from an initialization parameter the directory where
   * the bulletin files are stored.
   */
  public void init(ServletConfig config) throws    ServletException
  {
    super.init(config); //pass ServletConfig to parent

    //get path to support files
    filePath = config.getInitParameter("FilePath");
    if (filePath == null)
    {
      //default directory if no FilePath init parameter exists
      filePath = "/";
    }
  }


  /**
   * doGet method is called in response to any GET request.
   * Returns an HTML form that allows the user to select a
   * bulletin board topic and choose to view bulletins or post
   * a new one.
   */
  public void doGet(HttpServletRequest request,
    HttpServletResponse response) throws IOException
  {
    //MIME type to return is HTML
    response.setContentType("text/html");

    //get a handle to the output stream
    PrintWriter out = response.getWriter();

    FileInputStream fileTopics=null;

    try
    {
      //open input stream to topics.properties file
      fileTopics = new FileInputStream(filePath +
        "topics.properties");

      Properties propTopics = new Properties();
      propTopics.load(fileTopics); //load properties object

      //create enumeration from properties object
      Enumeration enumTopics = propTopics.propertyNames();

      //create HTML form to allow user to select a topic
      out.println("<HTML>");
      out.println("<HEAD>");
      out.println("<TITLE>Servlet Bulletin Board</TITLE>");
      out.println("</HEAD>");
      out.println("<BODY>");
      out.println("<H2>Servlet Bulletin Board</H2>");
      out.println("<BR><FORM METHOD=\"POST\">");
      out.println("Select Bulletin Board Topic: ");
      out.println("<SELECT NAME=\"TOPICS\">");

      String topic; //stores description of current topic

      //iterate through all topics in topics.properties file
      while (enumTopics.hasMoreElements())
      {
        //set topic variable to current topic in enumeration
        topic = (String)enumTopics.nextElement();

        //add each topic from properties file to drop-down list
        if (propTopics.getProperty(topic).equals(
          request.getParameter("curTopic")))
        {
          //if user has selected a topic, keep it selected
          out.println("<OPTION SELECTED>" +
          propTopics.getProperty(topic)    + "</OPTION>");
        }
        else
        {
          //not the selected topic, just add to drop-down list
          out.println("<OPTION>" +
            propTopics.getProperty(topic) + "</OPTION>");
        }
      }

      out.println("</SELECT><BR><BR><BR>");
      out.println("<INPUT TYPE=\"SUBMIT\" NAME=\"VIEW\" " +
        "VALUE=\"VIEW BULLETINS\"> ");
      out.println("<INPUT TYPE=\"SUBMIT\" NAME=\"POST\" " +
        "VALUE=\"POST BULLETIN\">");
      out.println("</FORM>");
      out.println("</BODY></HTML>");
    }
    catch (Exception e)
    {
      //send stack trace back to client
      sendErrorToClient(out, e);
    }
    finally
    {
      try
      {
        //close file input stream
        fileTopics.close();
      }
      catch (Exception e) {}
      try
      {
        //close output stream
        out.close();
      }
      catch (Exception e) {}
    }
  }


  /**
   * doPost method is called in response to any POST request.
   * This method determines if it was called in response to the
   * user selecting to view bulletins, post a bulletin, or
   * save a bulletin and responds accordingly.
   */
  public void doPost(HttpServletRequest request,
    HttpServletResponse response)
  {
    String currentTopic=""; //user's currently selected topic

    PrintWriter out=null;

    //get bulletin board topic selected from drop-down list
    currentTopic = request.getParameter("TOPICS");
    //get the name of file containing bulletins for this topic
    String file = filePath + currentTopic + ".txt";
    //get path to servlet for use in hyperlinks
    String servletPath = request.getServletPath();

    response.setContentType("text/html"); //html output

    try
    {
      out = response.getWriter(); //get handle to output stream

      out.println("<HTML>");
      out.println("<HEAD><TITLE>" + currentTopic +
        " Bulletin Board</TITLE></HEAD>");
      out.println("<BODY>");

      //View Bulletins
      if (request.getParameter("VIEW") != null)
      {
        showBulletins(out, currentTopic, file);
      }
      //Post a bulletin
      else if (request.getParameter("POST") != null)
      {
        //allows user to enter bulletin and submit it
        postBulletin(out, currentTopic);
      }
      //Save bulletin
      else
      {
        //saves the bulletin to file
        saveBulletin(out, currentTopic, file, request);
      }

      //create hyperlink to return to main page
      out.println("<BR><BR><A HREF=\"" + servletPath +
        "?curTopic=" + java.net.URLEncoder.encode(currentTopic)+
        "\">Return to Main Page</A>");

      out.println("</BODY></HTML>");
    }
    catch (Exception e)
    {
      //send stack trace back to client
      sendErrorToClient(out, e);
    }
  }


  /**
   * showBulletins method reads bulletins from disk and sends
   * them to the client. If file does not exist, client is
   * informed that the selected topic contains no bulletins.
   *
   * @param out Client output stream
   * @param currentTopic User's currently selected topic
   * @param file File containing bulletins for selected topic
   */
  private void showBulletins(PrintWriter out,
    String currentTopic, String file)
  {
    FileReader fr=null;
    BufferedReader br=null;

    try
    {
      File fileTopic = new File(file); //get handle to file
      if (fileTopic.exists()) //file exists, display it
      {
        fr = new FileReader(file);
        br = new BufferedReader(fr); //get file input stream

        out.println("<H2>" + currentTopic +
          " Bulletin Board</H2>");
        out.println("<H3>View Bulletins</H3>");

        String line = br.readLine();
        //iterate through each line of bulletin board file
        while (line != null)
        {
          //send bulletins to client
          out.println(line + "<BR>\n");
          line = br.readLine();
        }
      }
      else //file doesn't exist, display no bulletins message
      {
        out.println("This topic currently contains no " +
          "bulletins.");
      }
    }
    catch (Exception e)
    {
      //send stack trace back to client
      sendErrorToClient(out, e);
    }
    finally
    {
      try
      {
        br.close(); //close buffered reader
      }
      catch (Exception e) {}
      try
      {
        fr.close(); //close file reader
      }
      catch (Exception e) {}
    }
  }


  /**
   * postBulletin method generates the HTML form that allows
   * the user to enter a new bulletin.
   *
   * @param out Client output stream
   * @param currentTopic User's currently selected topic
   */
  private void postBulletin(PrintWriter out,
    String currentTopic)
  {
    //create HTML form to allow user to enter new bulletin
    out.println("<H2>" + currentTopic +    " Bulletin Board</H2>");
    out.println("<H3>Post Bulletin</H3><BR>");
    out.println("<FORM METHOD=\"POST\">");
    out.println("<P><TEXTAREA NAME=\"BULLETIN\" " +
      "COLS=\"65\" ROWS=\"3\"></TEXTAREA>");
    out.println("<BR><BR><BR><INPUT TYPE=\"SUBMIT\" " +
      "NAME=\"STORE\" VALUE=\"STORE BULLETIN\"><BR>");
    //include current topic in hidden field
    out.println("<INPUT TYPE=\"HIDDEN\" " +
      "NAME=\"TOPICS\" VALUE=\"" + currentTopic + "\">");
    out.println("</FORM>");
  }


  /**
   * saveBulletin method saves the bulletin to disk.
   *
   * @param out Client output stream
   * @param currentTopic User's currently selected topic
   * @param file File containing bulletins for selected topic
   * @param request HttpServletRequest object
   */
  private void saveBulletin(PrintWriter out,
    String currentTopic, String file,
    HttpServletRequest request)
  {
    FileWriter fw=null;
    PrintWriter pw=null;

    try
    {
      fw = new FileWriter(file, true);
      pw = new PrintWriter(fw); //get output stream to file
      //print separator
      pw.println("-----------------------------------");
      //print user's bulletin to file
      pw.println(request.getParameter("BULLETIN"));

      out.println("<H2>Bulletin Saved!</H2>");
    }
    catch (Exception e)
    {
      //send stack trace back to client
      sendErrorToClient(out, e);
    }
    finally
    {
      try
      {
        pw.flush(); //flush output stream to file
        pw.close(); //close print writer
      }
      catch (Exception e) {}
      try
      {
        fw.close(); //close file writer
      }
      catch (Exception e) {}
    }
  }

  /**
   * Return stack trace to client. Useful for debugging.
   *
   * @param out Client output stream
   * @param e Exception
   */
  private void sendErrorToClient(PrintWriter out, Exception e)
  {
    //send stack trace back to client and to standard out
    StringWriter stringError = new StringWriter();
    PrintWriter printError = new PrintWriter(stringError);
    e.printStackTrace(printError);
    String stackTrace = stringError.toString();

    //send error message to client
    out.println("<HTML><TITLE>Error</TITLE><BODY>");
    out.println("<H1>Servlet Error</H1><H4>Error</H4>" + e +
      "<H4>Stack Trace</H4>" + stackTrace + "</BODY></HTML>");

    //print stack trace to standard out
    System.out.println("Servlet Error: " + stackTrace);
  }
}