// swad_classroom.c: classrooms, laboratories or other classrooms where classes are taught

/*
    SWAD (Shared Workspace At a Distance),
    is a web platform developed at the University of Granada (Spain),
    and used to support university teaching.

    This file is part of SWAD core.
    Copyright (C) 1999-2019 Antonio Caņas Vargas

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************/
/********************************** Headers **********************************/
/*****************************************************************************/

#include <linux/stddef.h>	// For NULL
#include <malloc.h>		// For calloc, free
#include <string.h>		// For string functions

#include "swad_box.h"
#include "swad_database.h"
#include "swad_form.h"
#include "swad_global.h"
#include "swad_classroom.h"
#include "swad_table.h"

/*****************************************************************************/
/************** External global variables from others modules ****************/
/*****************************************************************************/

extern struct Globals Gbl;

/*****************************************************************************/
/***************************** Private constants *****************************/
/*****************************************************************************/

/*****************************************************************************/
/******************************* Private types *******************************/
/*****************************************************************************/

/*****************************************************************************/
/***************************** Private variables *****************************/
/*****************************************************************************/

static struct Classroom *Cla_EditingCla = NULL;	// Static variable to keep the classroom being edited

/*****************************************************************************/
/***************************** Private prototypes ****************************/
/*****************************************************************************/

static void Cla_GetParamClaOrder (void);
static bool Cla_CheckIfICanCreateClassrooms (void);
static void Cla_PutIconsListingClassrooms (void);
static void Cla_PutIconToEditClassrooms (void);
static void Cla_PutIconsEditingClassrooms (void);

static void Cla_EditClassroomsInternal (void);

static void Cla_ListClassroomsForEdition (void);
static void Cla_PutParamClaCod (long ClaCod);

static void Cla_RenameClassroom (Cns_ShrtOrFullName_t ShrtOrFullName);
static bool Cla_CheckIfClassroomNameExists (const char *FieldName,const char *Name,long ClaCod);
static void Cla_UpdateClaNameDB (long ClaCod,const char *FieldName,const char *NewClaName);

static void Cla_WriteCapacity (unsigned Capacity);

static void Cla_PutFormToCreateClassroom (void);
static void Cla_PutHeadClassrooms (void);
static void Cla_CreateClassroom (struct Classroom *Cla);

static void Cla_EditingClassroomConstructor (void);
static void Cla_EditingClassroomDestructor (void);

/*****************************************************************************/
/************************* List all the classrooms ***************************/
/*****************************************************************************/

#define A SIZE_MAX

void Cla_SeeClassrooms (void)
  {
   extern const char *Hlp_CENTRE_Classrooms;
   extern const char *Txt_Classrooms;
   extern const char *Txt_CLASSROOMS_HELP_ORDER[Cla_NUM_ORDERS];
   extern const char *Txt_CLASSROOMS_ORDER[Cla_NUM_ORDERS];
   extern const char *Txt_New_classroom;
   Cla_Order_t Order;
   unsigned NumCla;
   unsigned RowEvenOdd;

   /***** Trivial check *****/
   if (Gbl.Hierarchy.Ctr.CtrCod <= 0)		// No centre selected
      return;

   /***** Get parameter with the type of order in the list of classrooms *****/
   Cla_GetParamClaOrder ();

   /***** Get list of classrooms *****/
   Cla_GetListClassrooms (Cla_ALL_DATA);

   /***** Table head *****/
   Box_StartBox (NULL,Txt_Classrooms,Cla_PutIconsListingClassrooms,
		 Hlp_CENTRE_Classrooms,Box_NOT_CLOSABLE);
   Tbl_StartTableWideMargin (2);
   fprintf (Gbl.F.Out,"<tr>");
   for (Order  = (Cla_Order_t) 0;
	Order <= (Cla_Order_t) (Cla_NUM_ORDERS - 1);
	Order++)
     {
      fprintf (Gbl.F.Out,"<th class=\"LEFT_MIDDLE\">");
      Frm_StartForm (ActSeeCla);
      Par_PutHiddenParamUnsigned ("Order",(unsigned) Order);
      Frm_LinkFormSubmit (Txt_CLASSROOMS_HELP_ORDER[Order],"TIT_TBL",NULL);
      if (Order == Gbl.Classrooms.SelectedOrder)
	 fprintf (Gbl.F.Out,"<u>");
      fprintf (Gbl.F.Out,"%s",Txt_CLASSROOMS_ORDER[Order]);
      if (Order == Gbl.Classrooms.SelectedOrder)
	 fprintf (Gbl.F.Out,"</u>");
      fprintf (Gbl.F.Out,"</a>");
      Frm_EndForm ();
      fprintf (Gbl.F.Out,"</th>");
     }
   fprintf (Gbl.F.Out,"</tr>");

   /***** Write list of classrooms *****/
   for (NumCla = 0, RowEvenOdd = 1;
	NumCla < Gbl.Classrooms.Num;
	NumCla++, RowEvenOdd = 1 - RowEvenOdd)
     {
      /* Short name */
      fprintf (Gbl.F.Out,"<tr>"
			 "<td class=\"DAT LEFT_MIDDLE %s\">"
			 "%s"
			 "</td>",
	       Gbl.ColorRows[RowEvenOdd],
	       Gbl.Classrooms.Lst[NumCla].ShrtName);

      /* Full name */
      fprintf (Gbl.F.Out,"<td class=\"DAT LEFT_MIDDLE %s\">"
			 "%s"
			 "</td>",
	       Gbl.ColorRows[RowEvenOdd],
	       Gbl.Classrooms.Lst[NumCla].FullName);

      /* Capacity */
      fprintf (Gbl.F.Out,"<td class=\"DAT RIGHT_MIDDLE %s\">",
	       Gbl.ColorRows[RowEvenOdd]);
      Cla_WriteCapacity (Gbl.Classrooms.Lst[NumCla].Capacity);
      fprintf (Gbl.F.Out,"</td>");

      /* Location */
      fprintf (Gbl.F.Out,"<td class=\"DAT LEFT_MIDDLE %s\">"
			 "%s"
			 "</td>"
			 "</tr>",
	       Gbl.ColorRows[RowEvenOdd],
	       Gbl.Classrooms.Lst[NumCla].Location);
     }

   /***** End table *****/
   Tbl_EndTable ();

   /***** Button to create classroom *****/
   if (Cla_CheckIfICanCreateClassrooms ())
     {
      Frm_StartForm (ActEdiCla);
      Btn_PutConfirmButton (Txt_New_classroom);
      Frm_EndForm ();
     }

   /***** End box *****/
   Box_EndBox ();

   /***** Free list of classrooms *****/
   Cla_FreeListClassrooms ();
  }

/*****************************************************************************/
/******** Get parameter with the type or order in list of classrooms *********/
/*****************************************************************************/

static void Cla_GetParamClaOrder (void)
  {
   Gbl.Classrooms.SelectedOrder = (Cla_Order_t)
	                          Par_GetParToUnsignedLong ("Order",
                                                            0,
                                                            Cla_NUM_ORDERS - 1,
                                                            (unsigned long) Cla_ORDER_DEFAULT);
  }

/*****************************************************************************/
/******************** Check if I can create classrooms ***********************/
/*****************************************************************************/

static bool Cla_CheckIfICanCreateClassrooms (void)
  {
   return (bool) (Gbl.Usrs.Me.Role.Logged >= Rol_CTR_ADM);
  }

/*****************************************************************************/
/**************** Put contextual icons in list of classrooms *****************/
/*****************************************************************************/

static void Cla_PutIconsListingClassrooms (void)
  {
   /***** Put icon to edit classrooms *****/
   if (Cla_CheckIfICanCreateClassrooms ())
      Cla_PutIconToEditClassrooms ();
  }

/*****************************************************************************/
/******************** Put a link (form) to edit classrooms *******************/
/*****************************************************************************/

static void Cla_PutIconToEditClassrooms (void)
  {
   Ico_PutContextualIconToEdit (ActEdiCla,NULL);
  }

/*****************************************************************************/
/************************* Put forms to edit classrooms **********************/
/*****************************************************************************/

void Cla_EditClassrooms (void)
  {
   /***** Classroom constructor *****/
   Cla_EditingClassroomConstructor ();

   /***** Edit classrooms *****/
   Cla_EditClassroomsInternal ();

   /***** Classroom destructor *****/
   Cla_EditingClassroomDestructor ();
  }

static void Cla_EditClassroomsInternal (void)
  {
   extern const char *Hlp_CENTRE_Classrooms_edit;
   extern const char *Txt_Classrooms;

   /***** Get list of classrooms *****/
   Cla_GetListClassrooms (Cla_ALL_DATA);

   /***** Start box *****/
   Box_StartBox (NULL,Txt_Classrooms,Cla_PutIconsEditingClassrooms,
                 Hlp_CENTRE_Classrooms_edit,Box_NOT_CLOSABLE);

   /***** Put a form to create a new classroom *****/
   Cla_PutFormToCreateClassroom ();

   /***** Forms to edit current classrooms *****/
   if (Gbl.Classrooms.Num)
      Cla_ListClassroomsForEdition ();

   /***** End box *****/
   Box_EndBox ();

   /***** Free list of classrooms *****/
   Cla_FreeListClassrooms ();
  }

/*****************************************************************************/
/*************** Put contextual icons in edition of classrooms ***************/
/*****************************************************************************/

static void Cla_PutIconsEditingClassrooms (void)
  {
   /***** Put icon to view classrooms *****/
   Cla_PutIconToViewClassrooms ();
  }

/*****************************************************************************/
/************************ Put icon to view classrooms ************************/
/*****************************************************************************/

void Cla_PutIconToViewClassrooms (void)
  {
   extern const char *Txt_Classrooms;

   Lay_PutContextualLinkOnlyIcon (ActSeeCla,NULL,NULL,
                                  "classroom.svg",
                                  Txt_Classrooms);
  }

/*****************************************************************************/
/************************** List all the classrooms **************************/
/*****************************************************************************/

void Cla_GetListClassrooms (Cla_WhichData_t WhichData)
  {
   static const char *OrderBySubQuery[Cla_NUM_ORDERS] =
     {
      "ShortName",			// Cla_ORDER_BY_SHRT_NAME
      "FullName",			// Cla_ORDER_BY_FULL_NAME
      "Capacity DESC,ShortName",	// Cla_ORDER_BY_CAPACITY
      "Location,ShortName",		// Cla_ORDER_BY_LOCATION
     };
   MYSQL_RES *mysql_res;
   MYSQL_ROW row;
   unsigned long NumRows;
   unsigned NumCla;
   struct Classroom *Cla;

   /***** Get classrooms from database *****/
   switch (WhichData)
     {
      case Cla_ALL_DATA:
	 NumRows = DB_QuerySELECT (&mysql_res,"can not get classrooms",
				   "SELECT ClaCod,"
					  "ShortName,"
					  "FullName,"
					  "Capacity,"
					  "Location"
				   " FROM classrooms"
				   " WHERE CtrCod=%ld"
				   " ORDER BY %s",
				   Gbl.Hierarchy.Ctr.CtrCod,
				   OrderBySubQuery[Gbl.Classrooms.SelectedOrder]);
	 break;
      case Cla_ONLY_SHRT_NAME:
      default:
	 NumRows = DB_QuerySELECT (&mysql_res,"can not get classrooms",
				   "SELECT ClaCod,"
					  "ShortName"
				   " FROM classrooms"
				   " WHERE CtrCod=%ld"
				   " ORDER BY ShortName",
				   Gbl.Hierarchy.Ctr.CtrCod);
	 break;
     }

   /***** Count number of rows in result *****/
   if (NumRows) // Classrooms found...
     {
      Gbl.Classrooms.Num = (unsigned) NumRows;

      /***** Create list with courses in centre *****/
      if ((Gbl.Classrooms.Lst = (struct Classroom *) calloc (NumRows,sizeof (struct Classroom))) == NULL)
          Lay_NotEnoughMemoryExit ();

      /***** Get the classrooms *****/
      for (NumCla = 0;
	   NumCla < Gbl.Classrooms.Num;
	   NumCla++)
        {
         Cla = &(Gbl.Classrooms.Lst[NumCla]);

         /* Get next classroom */
         row = mysql_fetch_row (mysql_res);

         /* Get classroom code (row[0]) */
         if ((Cla->ClaCod = Str_ConvertStrCodToLongCod (row[0])) < 0)
            Lay_ShowErrorAndExit ("Wrong code of classroom.");

         /* Get the short name of the classroom (row[1]) */
         Str_Copy (Cla->ShrtName,row[1],
                   Cla_MAX_BYTES_SHRT_NAME);

         if (WhichData == Cla_ALL_DATA)
           {
	    /* Get the full name of the classroom (row[2]) */
	    Str_Copy (Cla->FullName,row[2],
		      Cla_MAX_BYTES_FULL_NAME);

	    /* Get seating capacity in this classroom (row[3]) */
	    if (sscanf (row[3],"%u",&Cla->Capacity) != 1)
	       Cla->Capacity = Cla_UNLIMITED_CAPACITY;

	    /* Get the full name of the classroom (row[4]) */
	    Str_Copy (Cla->Location,row[4],
		      Cla_MAX_BYTES_LOCATION);
           }
        }
     }
   else
      Gbl.Classrooms.Num = 0;

   /***** Free structure that stores the query result *****/
   DB_FreeMySQLResult (&mysql_res);
  }

/*****************************************************************************/
/************************** Get classroom full name **************************/
/*****************************************************************************/

void Cla_GetDataOfClassroomByCod (struct Classroom *Cla)
  {
   MYSQL_RES *mysql_res;
   MYSQL_ROW row;
   unsigned long NumRows;

   /***** Clear data *****/
   Cla->ShrtName[0] = '\0';
   Cla->FullName[0] = '\0';
   Cla->Capacity = Cla_UNLIMITED_CAPACITY;
   Cla->Location[0] = '\0';

   /***** Check if classroom code is correct *****/
   if (Cla->ClaCod > 0)
     {
      /***** Get data of a classroom from database *****/
      NumRows = DB_QuerySELECT (&mysql_res,"can not get data of a classroom",
			        "SELECT ShortName,"
				       "FullName,"
				       "Capacity,"
				       "Location"
				" FROM classrooms"
				" WHERE ClaCod=%ld",
				Cla->ClaCod);

      /***** Count number of rows in result *****/
      if (NumRows) // Classroom found...
        {
         /* Get row */
         row = mysql_fetch_row (mysql_res);

         /* Get the short name of the classroom (row[0]) */
         Str_Copy (Cla->ShrtName,row[0],
                   Cla_MAX_BYTES_SHRT_NAME);

         /* Get the full name of the classroom (row[1]) */
         Str_Copy (Cla->FullName,row[1],
                   Cla_MAX_BYTES_FULL_NAME);

         /* Get seating capacity in this classroom (row[2]) */
         if (sscanf (row[2],"%u",&Cla->Capacity) != 1)
            Cla->Capacity = Cla_UNLIMITED_CAPACITY;

         /* Get the location of the classroom (row[3]) */
         Str_Copy (Cla->Location,row[3],
                   Cla_MAX_BYTES_LOCATION);
        }

      /***** Free structure that stores the query result *****/
      DB_FreeMySQLResult (&mysql_res);
     }
  }

/*****************************************************************************/
/************************** Free list of classrooms **************************/
/*****************************************************************************/

void Cla_FreeListClassrooms (void)
  {
   if (Gbl.Classrooms.Lst)
     {
      /***** Free memory used by the list of classrooms in institution *****/
      free ((void *) Gbl.Classrooms.Lst);
      Gbl.Classrooms.Lst = NULL;
      Gbl.Classrooms.Num = 0;
     }
  }

/*****************************************************************************/
/************************* List all the classrooms ***************************/
/*****************************************************************************/

static void Cla_ListClassroomsForEdition (void)
  {
   unsigned NumCla;
   struct Classroom *Cla;

   /***** Write heading *****/
   Tbl_StartTableWide (2);
   Cla_PutHeadClassrooms ();

   /***** Write all the classrooms *****/
   for (NumCla = 0;
	NumCla < Gbl.Classrooms.Num;
	NumCla++)
     {
      Cla = &Gbl.Classrooms.Lst[NumCla];

      /* Put icon to remove classroom */
      fprintf (Gbl.F.Out,"<tr>"
	                 "<td class=\"BM\">");
      Frm_StartForm (ActRemCla);
      Cla_PutParamClaCod (Cla->ClaCod);
      Ico_PutIconRemove ();
      Frm_EndForm ();
      fprintf (Gbl.F.Out,"</td>");

      /* Classroom code */
      fprintf (Gbl.F.Out,"<td class=\"DAT RIGHT_MIDDLE\">"
	                 "%ld"
	                 "</td>",
               Cla->ClaCod);

      /* Classroom short name */
      fprintf (Gbl.F.Out,"<td class=\"LEFT_MIDDLE\">");
      Frm_StartForm (ActRenClaSho);
      Cla_PutParamClaCod (Cla->ClaCod);
      fprintf (Gbl.F.Out,"<input type=\"text\" name=\"ShortName\""
	                 " size=\"10\" maxlength=\"%u\" value=\"%s\""
                         " class=\"INPUT_SHORT_NAME\""
                         " onchange=\"document.getElementById('%s').submit();\" />",
               Cla_MAX_CHARS_SHRT_NAME,Cla->ShrtName,Gbl.Form.Id);
      Frm_EndForm ();
      fprintf (Gbl.F.Out,"</td>");

      /* Classroom full name */
      fprintf (Gbl.F.Out,"<td class=\"LEFT_MIDDLE\">");
      Frm_StartForm (ActRenClaFul);
      Cla_PutParamClaCod (Cla->ClaCod);
      fprintf (Gbl.F.Out,"<input type=\"text\" name=\"FullName\""
	                 " size=\"20\" maxlength=\"%u\" value=\"%s\""
                         " class=\"INPUT_FULL_NAME\""
                         " onchange=\"document.getElementById('%s').submit();\" />",
               Cla_MAX_CHARS_FULL_NAME,Cla->FullName,Gbl.Form.Id);
      Frm_EndForm ();
      fprintf (Gbl.F.Out,"</td>");

      /* Seating capacity */
      fprintf (Gbl.F.Out,"<td class=\"LEFT_MIDDLE\">");
      Frm_StartForm (ActChgClaMaxStd);
      Cla_PutParamClaCod (Cla->ClaCod);
      fprintf (Gbl.F.Out,"<input type=\"text\" name=\"Capacity\""
			 " size=\"3\" maxlength=\"10\" value=\"");
      Cla_WriteCapacity (Cla->Capacity);
      fprintf (Gbl.F.Out,"\" onchange=\"document.getElementById('%s').submit();\" />",
	       Gbl.Form.Id);
      Frm_EndForm ();
      fprintf (Gbl.F.Out,"</td>");

      /* Classroom location */
      fprintf (Gbl.F.Out,"<td class=\"LEFT_MIDDLE\">");
      Frm_StartForm (ActRenClaLoc);
      Cla_PutParamClaCod (Cla->ClaCod);
      fprintf (Gbl.F.Out,"<input type=\"text\" name=\"Location\""
	                 " size=\"15\" maxlength=\"%u\" value=\"%s\""
                         " class=\"INPUT_FULL_NAME\""
                         " onchange=\"document.getElementById('%s').submit();\" />",
               Cla_MAX_CHARS_LOCATION,Cla->Location,Gbl.Form.Id);
      Frm_EndForm ();
      fprintf (Gbl.F.Out,"</td>"
			 "</tr>");
     }

   /***** End table *****/
   Tbl_EndTable ();
  }

/*****************************************************************************/
/****************** Write parameter with code of classroom *******************/
/*****************************************************************************/

static void Cla_PutParamClaCod (long ClaCod)
  {
   Par_PutHiddenParamLong ("ClaCod",ClaCod);
  }

/*****************************************************************************/
/******************* Get parameter with code of classroom ********************/
/*****************************************************************************/

long Cla_GetParamClaCod (void)
  {
   /***** Get code of classroom *****/
   return Par_GetParToLong ("ClaCod");
  }

/*****************************************************************************/
/***************************** Remove a classroom ****************************/
/*****************************************************************************/

void Cla_RemoveClassroom (void)
  {
   extern const char *Txt_Classroom_X_removed;

   /***** Classroom constructor *****/
   Cla_EditingClassroomConstructor ();

   /***** Get classroom code *****/
   if ((Cla_EditingCla->ClaCod = Cla_GetParamClaCod ()) == -1L)
      Lay_ShowErrorAndExit ("Code of classroom is missing.");

   /***** Get data of the classroom from database *****/
   Cla_GetDataOfClassroomByCod (Cla_EditingCla);

   /***** Update groups assigned to this classroom *****/
   DB_QueryUPDATE ("can not update classroom in groups",
		   "UPDATE crs_grp SET ClaCod=0"	// 0 means another classroom
		   " WHERE ClaCod=%ld",
		   Cla_EditingCla->ClaCod);

   /***** Remove classroom *****/
   DB_QueryDELETE ("can not remove a classroom",
		   "DELETE FROM classrooms WHERE ClaCod=%ld",
		   Cla_EditingCla->ClaCod);

   /***** Create message to show the change made *****/
   Ale_CreateAlert (Ale_SUCCESS,NULL,
	            Txt_Classroom_X_removed,
	            Cla_EditingCla->FullName);
  }

/*****************************************************************************/
/******************** Remove all classrooms in a centre **********************/
/*****************************************************************************/

void Cla_RemoveAllClassroomsInCtr (long CtrCod)
  {
   /***** Remove all classrooms in centre *****/
   DB_QueryDELETE ("can not remove classrooms",
		   "DELETE FROM classrooms"
                   " WHERE CtrCod=%ld",
		   CtrCod);
  }

/*****************************************************************************/
/******************* Change the short name of a classroom ********************/
/*****************************************************************************/

void Cla_RenameClassroomShort (void)
  {
   /***** Classroom constructor *****/
   Cla_EditingClassroomConstructor ();

   /***** Rename classroom *****/
   Cla_RenameClassroom (Cns_SHRT_NAME);
  }

/*****************************************************************************/
/******************* Change the full name of a classroom *********************/
/*****************************************************************************/

void Cla_RenameClassroomFull (void)
  {
   /***** Classroom constructor *****/
   Cla_EditingClassroomConstructor ();

   /***** Rename classroom *****/
   Cla_RenameClassroom (Cns_FULL_NAME);
  }

/*****************************************************************************/
/********************** Change the name of a classroom ***********************/
/*****************************************************************************/

static void Cla_RenameClassroom (Cns_ShrtOrFullName_t ShrtOrFullName)
  {
   extern const char *Txt_You_can_not_leave_the_name_of_the_classroom_X_empty;
   extern const char *Txt_The_classroom_X_already_exists;
   extern const char *Txt_The_classroom_X_has_been_renamed_as_Y;
   extern const char *Txt_The_name_of_the_classroom_X_has_not_changed;
   const char *ParamName = NULL;	// Initialized to avoid warning
   const char *FieldName = NULL;	// Initialized to avoid warning
   unsigned MaxBytes = 0;		// Initialized to avoid warning
   char *CurrentClaName = NULL;		// Initialized to avoid warning
   char NewClaName[Cla_MAX_BYTES_FULL_NAME + 1];

   switch (ShrtOrFullName)
     {
      case Cns_SHRT_NAME:
         ParamName = "ShortName";
         FieldName = "ShortName";
         MaxBytes = Cla_MAX_BYTES_SHRT_NAME;
         CurrentClaName = Cla_EditingCla->ShrtName;
         break;
      case Cns_FULL_NAME:
         ParamName = "FullName";
         FieldName = "FullName";
         MaxBytes = Cla_MAX_BYTES_FULL_NAME;
         CurrentClaName = Cla_EditingCla->FullName;
         break;
     }

   /***** Get parameters from form *****/
   /* Get the code of the classroom */
   if ((Cla_EditingCla->ClaCod = Cla_GetParamClaCod ()) == -1L)
      Lay_ShowErrorAndExit ("Code of classroom is missing.");

   /* Get the new name for the classroom */
   Par_GetParToText (ParamName,NewClaName,MaxBytes);

   /***** Get from the database the old names of the classroom *****/
   Cla_GetDataOfClassroomByCod (Cla_EditingCla);

   /***** Check if new name is empty *****/
   if (!NewClaName[0])
      Ale_CreateAlert (Ale_WARNING,NULL,
	               Txt_You_can_not_leave_the_name_of_the_classroom_X_empty,
                       CurrentClaName);
   else
     {
      /***** Check if old and new names are the same
             (this happens when return is pressed without changes) *****/
      if (strcmp (CurrentClaName,NewClaName))	// Different names
        {
         /***** If classroom was in database... *****/
         if (Cla_CheckIfClassroomNameExists (ParamName,NewClaName,Cla_EditingCla->ClaCod))
            Ale_CreateAlert (Ale_WARNING,NULL,
        	             Txt_The_classroom_X_already_exists,
                             NewClaName);
         else
           {
            /* Update the table changing old name by new name */
            Cla_UpdateClaNameDB (Cla_EditingCla->ClaCod,FieldName,NewClaName);

            /* Write message to show the change made */
            Ale_CreateAlert (Ale_SUCCESS,NULL,
        	             Txt_The_classroom_X_has_been_renamed_as_Y,
                             CurrentClaName,NewClaName);
           }
        }
      else	// The same name
         Ale_CreateAlert (Ale_INFO,NULL,
                          Txt_The_name_of_the_classroom_X_has_not_changed,
                          CurrentClaName);
     }

   /***** Update classroom name *****/
   Str_Copy (CurrentClaName,NewClaName,
             MaxBytes);
  }

/*****************************************************************************/
/******************** Check if the name of classroom exists ******************/
/*****************************************************************************/

static bool Cla_CheckIfClassroomNameExists (const char *FieldName,const char *Name,long ClaCod)
  {
   /***** Get number of classrooms with a name from database *****/
   return (DB_QueryCOUNT ("can not check if the name of a classroom"
			  " already existed",
			  "SELECT COUNT(*) FROM classrooms"
			  " WHERE CtrCod=%ld"
			  " AND %s='%s' AND ClaCod<>%ld",
			  Gbl.Hierarchy.Ctr.CtrCod,
			  FieldName,Name,ClaCod) != 0);
  }

/*****************************************************************************/
/************** Update classroom name in table of classrooms *****************/
/*****************************************************************************/

static void Cla_UpdateClaNameDB (long ClaCod,const char *FieldName,const char *NewClaName)
  {
   /***** Update classroom changing old name by new name */
   DB_QueryUPDATE ("can not update the name of a classroom",
		   "UPDATE classrooms SET %s='%s' WHERE ClaCod=%ld",
		   FieldName,NewClaName,ClaCod);
  }

/*****************************************************************************/
/****************** Change sitting capacity of a classroom *******************/
/*****************************************************************************/

void Cla_ChangeCapacity (void)
  {
   extern const char *Txt_The_capacity_of_classroom_X_has_not_changed;
   extern const char *Txt_The_classroom_X_does_not_have_a_limited_capacity_now;
   extern const char *Txt_The_capacity_of_classroom_X_is_now_Y;
   unsigned NewCapacity;

   /***** Classroom constructor *****/
   Cla_EditingClassroomConstructor ();

   /***** Get parameters from form *****/
   /* Get the code of the classroom */
   if ((Cla_EditingCla->ClaCod = Cla_GetParamClaCod ()) == -1L)
      Lay_ShowErrorAndExit ("Code of classroom is missing.");

   /* Get the seating capacity of the classroom */
   NewCapacity = (unsigned)
	          Par_GetParToUnsignedLong ("Capacity",
                                            0,
                                            Cla_MAX_CAPACITY,
                                            Cla_UNLIMITED_CAPACITY);

   /***** Get data of the classroom from database *****/
   Cla_GetDataOfClassroomByCod (Cla_EditingCla);

   /***** Check if the old capacity equals the new one
          (this happens when return is pressed without changes) *****/
   if (Cla_EditingCla->Capacity == NewCapacity)
      /***** Message to show no changes made *****/
      Ale_CreateAlert (Ale_INFO,NULL,
	               Txt_The_capacity_of_classroom_X_has_not_changed,
		       Cla_EditingCla->FullName);
   else
     {
      /***** Update the table of groups changing the old capacity to the new *****/
      DB_QueryUPDATE ("can not update the capacity of a classroom",
		      "UPDATE classrooms SET Capacity=%u WHERE ClaCod=%ld",
                      NewCapacity,Cla_EditingCla->ClaCod);
      Cla_EditingCla->Capacity = NewCapacity;

      /***** Message to show the change made *****/
      if (NewCapacity > Grp_MAX_STUDENTS_IN_A_GROUP)
         Ale_CreateAlert (Ale_SUCCESS,NULL,
                          Txt_The_classroom_X_does_not_have_a_limited_capacity_now,
                          Cla_EditingCla->FullName);
      else
         Ale_CreateAlert (Ale_SUCCESS,NULL,
                          Txt_The_capacity_of_classroom_X_is_now_Y,
                          Cla_EditingCla->FullName,NewCapacity);
     }
  }

/*****************************************************************************/
/****************** Write seating capacity of a classroom ********************/
/*****************************************************************************/

static void Cla_WriteCapacity (unsigned Capacity)
  {
   if (Capacity <= Cla_MAX_CAPACITY)
      fprintf (Gbl.F.Out,"%u",Capacity);
  }

/*****************************************************************************/
/******************** Change the location of a classroom *********************/
/*****************************************************************************/

void Cla_ChangeClassroomLocation (void)
  {
   extern const char *Txt_The_location_of_the_classroom_X_has_changed_to_Y;
   extern const char *Txt_The_location_of_the_classroom_X_has_not_changed;
   char NewLocation[Cla_MAX_BYTES_FULL_NAME + 1];

   /***** Classroom constructor *****/
   Cla_EditingClassroomConstructor ();

   /***** Get parameters from form *****/
   /* Get the code of the classroom */
   if ((Cla_EditingCla->ClaCod = Cla_GetParamClaCod ()) == -1L)
      Lay_ShowErrorAndExit ("Code of classroom is missing.");

   /* Get the new location for the classroom */
   Par_GetParToText ("Location",NewLocation,Cla_MAX_BYTES_LOCATION);

   /***** Get from the database the old location of the classroom *****/
   Cla_GetDataOfClassroomByCod (Cla_EditingCla);

   /***** Check if old and new locations are the same
	  (this happens when return is pressed without changes) *****/
   if (strcmp (Cla_EditingCla->Location,NewLocation))	// Different locations
     {
      /* Update the table changing old name by new name */
      Cla_UpdateClaNameDB (Cla_EditingCla->ClaCod,"Location",NewLocation);
      Str_Copy (Cla_EditingCla->Location,NewLocation,
		Cla_MAX_BYTES_LOCATION);

      /* Write message to show the change made */
      Ale_CreateAlert (Ale_SUCCESS,NULL,
	               Txt_The_location_of_the_classroom_X_has_changed_to_Y,
		       Cla_EditingCla->FullName,NewLocation);
     }
   else	// The same location
      Ale_CreateAlert (Ale_INFO,NULL,
	               Txt_The_location_of_the_classroom_X_has_not_changed,
		       Cla_EditingCla->FullName);
  }

/*****************************************************************************/
/******* Show alerts after changing a classroom and continue editing *********/
/*****************************************************************************/

void Cla_ContEditAfterChgCla (void)
  {
   /***** Write message to show the change made *****/
   Ale_ShowAlerts (NULL);

   /***** Show the form again *****/
   Cla_EditClassroomsInternal ();

   /***** Classroom destructor *****/
   Cla_EditingClassroomDestructor ();
  }

/*****************************************************************************/
/******************* Put a form to create a new classroom ********************/
/*****************************************************************************/

static void Cla_PutFormToCreateClassroom (void)
  {
   extern const char *Txt_New_classroom;
   extern const char *Txt_Create_classroom;

   /***** Start form *****/
   Frm_StartForm (ActNewCla);

   /***** Start box and table *****/
   Box_StartBoxTable (NULL,Txt_New_classroom,NULL,
                      NULL,Box_NOT_CLOSABLE,2);

   /***** Write heading *****/
   Cla_PutHeadClassrooms ();

   /***** Column to remove classroom, disabled here *****/
   fprintf (Gbl.F.Out,"<tr>"
		      "<td class=\"BM\"></td>");

   /***** Classroom code *****/
   fprintf (Gbl.F.Out,"<td class=\"CODE\"></td>");

   /***** Classroom short name *****/
   fprintf (Gbl.F.Out,"<td class=\"LEFT_MIDDLE\">"
                      "<input type=\"text\" name=\"ShortName\""
                      " size=\"10\" maxlength=\"%u\" value=\"%s\""
                      " class=\"INPUT_SHORT_NAME\""
                      " required=\"required\" />"
                      "</td>",
            Cla_MAX_CHARS_SHRT_NAME,Cla_EditingCla->ShrtName);

   /***** Classroom full name *****/
   fprintf (Gbl.F.Out,"<td class=\"LEFT_MIDDLE\">"
                      "<input type=\"text\" name=\"FullName\""
                      " size=\"20\" maxlength=\"%u\" value=\"%s\""
                      " class=\"INPUT_FULL_NAME\""
                      " required=\"required\" />"
                      "</td>",
            Cla_MAX_CHARS_FULL_NAME,Cla_EditingCla->FullName);

   /***** Seating capacity *****/
   fprintf (Gbl.F.Out,"<td class=\"LEFT_MIDDLE\">"
	              "<input type=\"text\" name=\"Capacity\""
	              " size=\"3\" maxlength=\"10\" value=\"");
   Cla_WriteCapacity (Cla_EditingCla->Capacity);
   fprintf (Gbl.F.Out,"\" />"
	              "</td>");

   /***** Classroom location *****/
   fprintf (Gbl.F.Out,"<td class=\"LEFT_MIDDLE\">"
                      "<input type=\"text\" name=\"Location\""
		      " size=\"15\" maxlength=\"%u\" value=\"%s\""
		      " class=\"INPUT_FULL_NAME\" />"
	              "</td>"
		      "</tr>",
	    Cla_MAX_CHARS_LOCATION,Cla_EditingCla->Location);

   /***** End table, send button and end box *****/
   Box_EndBoxTableWithButton (Btn_CREATE_BUTTON,Txt_Create_classroom);

   /***** End form *****/
   Frm_EndForm ();
  }

/*****************************************************************************/
/****************** Write header with fields of a classroom ******************/
/*****************************************************************************/

static void Cla_PutHeadClassrooms (void)
  {
   extern const char *Txt_Code;
   extern const char *Txt_Short_name;
   extern const char *Txt_Full_name;
   extern const char *Txt_Capacity_OF_A_CLASSROOM;
   extern const char *Txt_Location;

   fprintf (Gbl.F.Out,"<tr>"
                      "<th class=\"BM\"></th>"
                      "<th class=\"RIGHT_MIDDLE\">"
                      "%s"
                      "</th>"
                      "<th class=\"LEFT_MIDDLE\">"
                      "%s"
                      "</th>"
                      "<th class=\"LEFT_MIDDLE\">"
                      "%s"
                      "</th>"
                      "<th class=\"LEFT_MIDDLE\">"
                      "%s"
                      "</th>"
                      "<th class=\"LEFT_MIDDLE\">"
                      "%s"
                      "</th>"
		      "</tr>",
            Txt_Code,
            Txt_Short_name,
            Txt_Full_name,
            Txt_Capacity_OF_A_CLASSROOM,
            Txt_Location);
  }

/*****************************************************************************/
/***************** Receive form to create a new classroom ********************/
/*****************************************************************************/

void Cla_RecFormNewClassroom (void)
  {
   extern const char *Txt_The_classroom_X_already_exists;
   extern const char *Txt_Created_new_classroom_X;
   extern const char *Txt_You_must_specify_the_short_name_and_the_full_name_of_the_new_classroom;

   /***** Classroom constructor *****/
   Cla_EditingClassroomConstructor ();

   /***** Get parameters from form *****/
   /* Get classroom short name */
   Par_GetParToText ("ShortName",Cla_EditingCla->ShrtName,Cla_MAX_BYTES_SHRT_NAME);

   /* Get classroom full name */
   Par_GetParToText ("FullName",Cla_EditingCla->FullName,Cla_MAX_BYTES_FULL_NAME);

   /* Get seating capacity */
   Cla_EditingCla->Capacity = (unsigned)
	                      Par_GetParToUnsignedLong ("Capacity",
                                                        0,
                                                        Cla_MAX_CAPACITY,
                                                        Cla_UNLIMITED_CAPACITY);

   /* Get classroom location */
   Par_GetParToText ("Location",Cla_EditingCla->Location,Cla_MAX_BYTES_LOCATION);

   if (Cla_EditingCla->ShrtName[0] &&
       Cla_EditingCla->FullName[0])	// If there's a classroom name
     {
      /***** If name of classroom was in database... *****/
      if (Cla_CheckIfClassroomNameExists ("ShortName",Cla_EditingCla->ShrtName,-1L))
         Ale_CreateAlert (Ale_WARNING,NULL,
                          Txt_The_classroom_X_already_exists,
                          Cla_EditingCla->ShrtName);
      else if (Cla_CheckIfClassroomNameExists ("FullName",Cla_EditingCla->FullName,-1L))
         Ale_CreateAlert (Ale_WARNING,NULL,
                          Txt_The_classroom_X_already_exists,
                          Cla_EditingCla->FullName);
      else	// Add new classroom to database
        {
         Cla_CreateClassroom (Cla_EditingCla);
	 Ale_CreateAlert (Ale_SUCCESS,NULL,
	                  Txt_Created_new_classroom_X,
			  Cla_EditingCla->FullName);
        }
     }
   else	// If there is not a classroom name
      Ale_CreateAlert (Ale_WARNING,NULL,
	               Txt_You_must_specify_the_short_name_and_the_full_name_of_the_new_classroom);
  }

/*****************************************************************************/
/************************** Create a new classroom ***************************/
/*****************************************************************************/

static void Cla_CreateClassroom (struct Classroom *Cla)
  {
   /***** Create a new classroom *****/
   DB_QueryINSERT ("can not create classroom",
		   "INSERT INTO classrooms"
		   " (CtrCod,ShortName,FullName,Capacity,Location)"
		   " VALUES"
		   " (%ld,'%s','%s',%u,'%s')",
                   Gbl.Hierarchy.Ctr.CtrCod,
		   Cla->ShrtName,Cla->FullName,Cla->Capacity,Cla->Location);
  }

/*****************************************************************************/
/************************* Classroom constructor/destructor **********************/
/*****************************************************************************/

static void Cla_EditingClassroomConstructor (void)
  {
   /***** Pointer must be NULL *****/
   if (Cla_EditingCla != NULL)
      Lay_ShowErrorAndExit ("Error initializing classroom.");

   /***** Allocate memory for classroom *****/
   if ((Cla_EditingCla = (struct Classroom *) malloc (sizeof (struct Classroom))) == NULL)
      Lay_ShowErrorAndExit ("Error allocating memory for classroom.");

   /***** Reset classroom *****/
   Cla_EditingCla->ClaCod      = -1L;
   Cla_EditingCla->InsCod      = -1L;
   Cla_EditingCla->ShrtName[0] = '\0';
   Cla_EditingCla->FullName[0] = '\0';
   Cla_EditingCla->Capacity    = Cla_UNLIMITED_CAPACITY;
   Cla_EditingCla->Location[0] = '\0';
  }

static void Cla_EditingClassroomDestructor (void)
  {
   /***** Free memory used for classroom *****/
   if (Cla_EditingCla != NULL)
     {
      free ((void *) Cla_EditingCla);
      Cla_EditingCla = NULL;
     }
  }
