/*
 * CallButton.java
 *
 * Copyright 2013 John W Dawson
 *
 * This code is distributed under the terms of the GNU General Public License, version 3
 *
 * This class implements the buttons that call numbers stored in phone number fields
 */

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.net.URL;
import java.io.*;
import java.net.*;
import javax.net.ssl.HttpsURLConnection;
import java.util.regex.*;
import java.util.logging.*;
public class CallButton extends JButton implements ActionListener
{
  static Logger log = Logger.getLogger ("LdapAddressBook");
  private static final String PHONE_IMAGE = "images/phone12.png";
  static Pattern numberPattern = Pattern.compile ("[^\\d\\*]");
  static Pattern hostPattern = Pattern.compile ("(http(s)?://)?(\\w+(\\.\\w+)*)");
  private ExtensionSelector extensionSelector;
  private MessageLine messageLine;
  private AddressBookTextField numberField;
     
  public CallButton (AddressBookTextField numberField, ExtensionSelector extensionSelector, MessageLine messageLine)
  {
    super ();
    setIcon (new ImageIcon (getClass().getResource (PHONE_IMAGE)));
    int height = (int) getPreferredSize().getHeight();
    setPreferredSize (new Dimension (height, height));
    setEnabled (false);
    this.addActionListener (this);
    this.extensionSelector = extensionSelector;
    this.messageLine = messageLine;
    this.numberField = numberField;
  }

  // This class is used to construct the parameter string for the POST request 
  private class ParameterStringBuffer
  {
    StringBuffer buff = new StringBuffer ();
    
    public void add (String parameter, ConfigurationRecord extension, ConfigurationRecord provider)
    throws UnsupportedEncodingException
    {
      String value = extension.getElementValue (parameter);
      add (parameter, provider, value);
    }
    
    public void add (String parameter, ConfigurationRecord provider, String value)
    throws UnsupportedEncodingException
    {
      String key = provider.getElementValue ("post" + parameter + "parameter");
      if (key != null)
      {
        buff.append ((buff.length() == 0 ? "" : "&") + URLEncoder.encode(key, "UTF-8") + "=" + URLEncoder.encode(value, "UTF-8"));
      }
    }

    public void add (String parameter)
    {
      if (parameter != null)
      {
        buff.append ("&");
        buff.append (parameter);
      }
    }       
    
    public String toString ()
    {
      return buff.toString ();
    }
  }
  
  public void actionPerformed (ActionEvent event)
  {
    try
    {
      // Get number from field
      String number = this.numberField.getText ();
      messageLine.setTransientText ("Dialling: " + number);
      
      // Get the currently selected extension and its provider
      ConfigurationRecord extension = extensionSelector.getSelectedExtension ();
      ConfigurationRecord provider = extension.getParentRecord ();
      
      // Construct parameter string
      ParameterStringBuffer parameters = new ParameterStringBuffer ();
      parameters.add ("extensionnumber", extension, provider);
      parameters.add ("username", extension, provider);
      parameters.add ("password", provider, extension.getEncryptedValue ("password"));
      
      // Sanitise number if required by removing all characters except digits
      if (provider.getBooleanValue ("sanitise"))
      {
        Matcher matcher = numberPattern.matcher (number);
        number = matcher.replaceAll ("");
      }
      parameters.add ("numbertocall", provider, number);
      
      // Add any additional parameters
      parameters.add (provider.getElementValue ("postextraparameters"));
      
      // Open connection to server
      String postURL = provider.getElementValue("posturl");
      Matcher hostMatcher = hostPattern.matcher(postURL);
      hostMatcher.find();
      String hostName = hostMatcher.group(3);
      try
      {
        HttpURLConnection conn = (HttpURLConnection) (new URL(postURL)).openConnection();
        
        // Get output stream and write parameters
        conn.setDoOutput(true);
        OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream());
        writer.write(parameters.toString());
        writer.flush();
        writer.close();
      
        // Check response code
        int response = conn.getResponseCode ();
        if (response == HttpURLConnection.HTTP_OK)
        {
        
          // Read the 1st line of response and check it conforms to the pattern for success
          BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
          String line = rd.readLine();
          while (rd.readLine() != null) {}
          rd.close();
          conn.disconnect ();
          String okResponse = provider.getElementValue ("okresponse");
          if (okResponse != null && line != null)
          {
            Pattern okPattern = Pattern.compile (okResponse);
            Matcher okMatcher = okPattern.matcher (line);
            if (!okMatcher.matches ())
            {
              JOptionPane.showMessageDialog (this, "The POST request failed: " + response + " - " + line, 
                                             "Call connection failure", JOptionPane.ERROR_MESSAGE);
              return;
            }
          }

          // Log the call      
          log.info ("Call to " + number + " from extension " + extension.getElementValue ("extensionnumber") +
                         " (" + extension.toString () + ")");
                         
          // Save the extension used 
          extensionSelector.saveSelectedExtension ();
        }
        else if (response == HttpURLConnection.HTTP_NOT_FOUND)
        {
          JOptionPane.showMessageDialog (this, "The URL " + postURL + " could not be found", 
                                         "Call connection failure", JOptionPane.ERROR_MESSAGE);
          conn.disconnect ();
        }
        else
        {
          JOptionPane.showMessageDialog (this, "The POST request failed: " + response + " - " + conn.getResponseMessage(), 
                                         "Call connection failure", JOptionPane.ERROR_MESSAGE);
          conn.disconnect ();
        }
      }
      catch (UnknownHostException e)
      {
        JOptionPane.showMessageDialog (this, "The host " + hostName + " could not be found", 
                                       "Call connection failure", JOptionPane.ERROR_MESSAGE);
      }
      catch (java.net.SocketException e)
      {
        JOptionPane.showMessageDialog (this, "Unable to connect to host " + hostName, 
                                       "Call connection failure", JOptionPane.ERROR_MESSAGE);
      }
      catch (javax.net.ssl.SSLHandshakeException e)
      {
        JOptionPane.showMessageDialog (this, "SSL certificate for host " + hostName + " is not signed by a trusted provider", 
                                       "Call connection failure", JOptionPane.ERROR_MESSAGE);
      }
    }
    catch (Exception e)
    {
      System.out.println(e.getMessage());
      e.printStackTrace();
    }  
  }
}
	