#ifndef TTY_H
#define TTY_H
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>

#include <unistd.h>
#include <signal.h>
#include <stdint.h>
#include <iostream>
#include "xtty.h"

using namespace std;

namespace hierarchy_memory {
namespace tty          {

  class param_t
  {
  public : char   * name;
  public : uint32_t nb_tty;
  public : char  ** name_tty;
  public : bool     with_xtty;

  public : param_t () {};

  public : param_t (char   * name    ,
		    uint32_t nb_tty  ,
		    char  ** name_tty,
		    bool     with_xtty)
    {
      this->name     = name;
      this->nb_tty   = nb_tty;
      this->name_tty = name_tty;
      this->with_xtty = with_xtty;
    }
  };

  class Tty
  {
  private   : char           * name;
  protected : const uint32_t   nb_tty;
  private   : const bool       with_xtty;
  private   : xtty_t         * xtty;

  public : Tty (param_t param):
    nb_tty    (param.nb_tty),
    with_xtty  (param.with_xtty)
    {
      uint32_t size_name = strlen(param.name)+1;
      name = new char [size_name];
      strncpy(name,param.name,size_name);

      xtty = new xtty_t [nb_tty];

      for (uint32_t i = 0; i < nb_tty; i++)
	{
	  // ***** Create a log_file *****
	  xtty [i].log_file = fopen(param.name_tty[i],"w");

	  if (xtty [i].log_file == NULL)
	    {
	      // Error
	      cerr << "<Tty> Can't open the file : \"" << param.name_tty[i] << "\"" << endl;
	      exit(1);
	    }

	  if (with_xtty == true)
	    {
	      // ***** TTY and pipe init *****
	      canal canal_output;
	      
	      if (pipe (canal_output.CanalPipe) != 0)
		{
		  cerr << "<Tty> Error in pipe creation" << endl;
		  exit(1);
		}
	      
	      if ((xtty[i].pid = fork()) == 0)
		{
		  // Childen -> transform in a xtty
		  close(0);
		  dup (canal_output.CanalPipe [0]);
		  close(1);
		  execlp("xtty","xtty", param.name_tty [i] ,NULL); // devient un tty
		  
		  cerr << "<Tty> Error in the creation of tty" << endl;
		  exit (1);
		}
	      else
		{
		  // father
		  xtty[i].pipe_output = canal_output.CanalPipe [1];
		}
	    }
	}//end for
    }

  public : ~Tty ()
    {
      // Kill all tty
      for (unsigned int i=0; i<nb_tty; i++)
      {
	if (with_xtty == true)
	  if (xtty[i].pid)
	    kill(xtty[i].pid,SIGTERM);
	fclose(xtty[i].log_file);
      }

    }
  public : void reset ()
    {
    }

    //*****[ write ]*****
  public : bool write (uint32_t num_tty, char data)
    {
      if (num_tty >= nb_tty)
	return false;
      char write_data = data;

      if (with_xtty == true)
	::write (xtty[num_tty].pipe_output, &write_data, 1);
      fputc (data, xtty[num_tty].log_file);

      return true;
    }

    public    : friend ostream& operator<< (ostream& output_stream, const Tty & x)
      {
	output_stream << "<" << x.name << ">" << endl;
	output_stream << " * nb_tty        : " << x.nb_tty      << endl;

	return output_stream;
      };
  };

};}; //end namespace
#endif //!TTY_H
