/*+++++++++++++++++++++++++++++
  authorinfo.c: functions to fiddle with author names
  markus@mhoenicka.de 2003-10-03

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 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 General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, see <http://www.gnu.org/licenses/>

   ++++++++++++++++++++++++++*/

#include <stdlib.h>
#include <string.h>

#include "strfncs.h"
#include "authorinfo.h"

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  assemble_full_author(): assembles a normalized full author name
                          from the name parts

  char* assemble_full_author returns ptr to a malloc'ed string which
                          the calling function has to free

  struct AUTHOR_INFO* ptr_ainfo ptr to struct containing the name
                      parts

  int* ptr_error ptr to an error counter, will be incremented in
                      case of an error

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* assemble_full_author(struct AUTHOR_INFO* ptr_ainfo, int* ptr_error) {
  char* item;
  char* temp_author;
  char* temp_middle;
  char* new_temp_author;
  char bitsandpieces[6];
  size_t temp_author_len = 256;

  if ((temp_author = malloc(temp_author_len)) == NULL) {
    (*ptr_error)++;
    return NULL;
  }

  if ((new_temp_author = mstrcpy(temp_author, ptr_ainfo->lastname, &temp_author_len)) == NULL) {
    (*ptr_error)++;
    free(temp_author);
    return NULL;
  }
  else {
    temp_author = new_temp_author;
  }

  if (*(ptr_ainfo->firstname)) {
    if ((new_temp_author = mstrcat(temp_author, ",", &temp_author_len, 0)) == NULL) {
      (*ptr_error)++;
      free(temp_author);
      return NULL;
    }
    else {
      temp_author = new_temp_author;
    }

    /* we've got to analyze whether this is a full first name or some
       hyphenated double initial */
    if (ptr_ainfo->firstname[1] == '-') {
      *bitsandpieces = *(ptr_ainfo->firstname);
      *(bitsandpieces + 1) = '.';
      *(bitsandpieces + 2) = '-';
      *(bitsandpieces + 3) = *(ptr_ainfo->firstname + 2);
      *(bitsandpieces + 4) = '.';
      *(bitsandpieces + 5) = '\0';
    }
    else if (*(ptr_ainfo->firstname + 1) == '\0') {
      *bitsandpieces = *ptr_ainfo->firstname;
      *(bitsandpieces + 1) = '.';
      *(bitsandpieces + 2) = '\0';
    }
    else {
      *bitsandpieces = '\0';
    }

    if (*bitsandpieces) {
      if ((new_temp_author = mstrcat(temp_author, bitsandpieces, &temp_author_len, 0)) == NULL) {
	(*ptr_error)++;
	free(temp_author);
	return NULL;
      }
      else {
	temp_author = new_temp_author;
      }
    }
    else {
      if ((new_temp_author = mstrcat(temp_author, ptr_ainfo->firstname, &temp_author_len, 0)) == NULL) {
	(*ptr_error)++;
	free(temp_author);
	return NULL;
      }
      else {
	temp_author = new_temp_author;
      }
    }
  }

  if (*(ptr_ainfo->middlename)) {
    if ((temp_middle = strdup(ptr_ainfo->middlename)) == NULL) {
      (*ptr_error)++;
      free(temp_author);
      return NULL;
    }

    for (item = strtok(temp_middle, " "); item; item = strtok(NULL, " ")) {
      if (temp_author[strlen(temp_author)-1] != '.') {
	if ((new_temp_author = mstrcat(temp_author, " ", &temp_author_len, 0)) == NULL) {
	  (*ptr_error)++;
	  free(temp_author);
	  free(temp_middle);
	  return NULL;
	}
	else {
	  temp_author = new_temp_author;
	}
      }

      /* check whether middle name is hyphenated initial */
      if (*(item + 1) == '-') {
	*bitsandpieces = *item;
	*(bitsandpieces + 1) = '.';
	*(bitsandpieces + 2) = '-';
	*(bitsandpieces + 3) = *(item + 2);
	*(bitsandpieces + 4) = '.';
	*(bitsandpieces + 5) = '\0';
      }
      else if (*(item + 1) == '\0') {
	*bitsandpieces = *item;
	*(bitsandpieces + 1) = '.';
	*(bitsandpieces + 2) = '\0';
      }
      else {
	*bitsandpieces = '\0';
      }

      if (*bitsandpieces) {
	if ((new_temp_author = mstrcat(temp_author, bitsandpieces, &temp_author_len, 0)) == NULL) {
	  (*ptr_error)++;
	  free(temp_author);
	  free(temp_middle);
	  return NULL;
	}
	else {
	  temp_author = new_temp_author;
	}
      }
      else {
	if ((new_temp_author = mstrcat(temp_author, item, &temp_author_len, 0)) == NULL) {
	  (*ptr_error)++;
	  free(temp_author);
	  free(temp_middle);
	  return NULL;
	}
	else {
	  temp_author = new_temp_author;
	}
      }
    } /* end for */
    free(temp_middle);
  } /* end if middlename */
	
  if (*(ptr_ainfo->suffix)) {
    if ((new_temp_author = mstrcat(temp_author, ",", &temp_author_len, 0)) == NULL) {
      (*ptr_error)++;
      free(temp_author);
      return NULL;
    }
    else {
      temp_author = new_temp_author;
    }
    
    if ((new_temp_author = mstrcat(temp_author, ptr_ainfo->suffix, &temp_author_len, 0)) == NULL) {
      (*ptr_error)++;
      free(temp_author);
      return NULL;
    }
    else {
      temp_author = new_temp_author;
    }
  }

  return temp_author;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  new_authorinfo(): creates a new authorinfo object

  struct AUTHOR_INFO* new_authorinfo returns ptr to a malloc'ed struct
                          which the calling function has to free by
			  using free_authorinfo()

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
struct AUTHOR_INFO* new_authorinfo(void) {
  struct AUTHOR_INFO* ptr_ainfo;

  ptr_ainfo = malloc(sizeof(struct AUTHOR_INFO)); 

  if (!ptr_ainfo) {
    return NULL;
  }
  else {
    reset_authorinfo(ptr_ainfo);
    return ptr_ainfo;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  reset_authorinfo(): resets the member variables

  void reset_authorinfo returns nothing

  struct AUTHOR_INFO* ptr_ainfo ptr to authorinfo structure

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void reset_authorinfo(struct AUTHOR_INFO* ptr_ainfo) {
  if (ptr_ainfo) {
    *(ptr_ainfo->name) = '\0';
    *(ptr_ainfo->lastname) = '\0';
    *(ptr_ainfo->firstname) = '\0';
    *(ptr_ainfo->middlename) = '\0';
    *(ptr_ainfo->suffix) = '\0';
    *(ptr_ainfo->role) = '\0';
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  set_authorinfo_name(): sets the name member variable to a new value
                         the name will be cropped if too long

  char* set_authorinfo_name returns a ptr to the name member variable
                         or NULL if at least one of the arguments is
			 NULL

  struct AUTHOR_INFO* ptr_ainfo ptr to authorinfo structure

  const char* name ptr to string with the name

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* set_authorinfo_name(struct AUTHOR_INFO* ptr_ainfo, const char* name) {
  if (!ptr_ainfo || !name) {
    return NULL;
  }

  /* truncate string */
  strncpy(ptr_ainfo->name, name, 255);
  (ptr_ainfo->name)[255] = '\0';
  return ptr_ainfo->name;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  set_authorinfo_lastname(): sets the lastname member variable to a new value
                         the lastname will be cropped if too long

  char* set_authorinfo_lastname returns a ptr to the lastname member variable
                         or NULL if at least one of the arguments is
			 NULL

  struct AUTHOR_INFO* ptr_ainfo ptr to authorinfo structure

  const char* lastname ptr to string with the lastname

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* set_authorinfo_lastname(struct AUTHOR_INFO* ptr_ainfo, const char* lastname) {
  if (!ptr_ainfo || !lastname) {
    return NULL;
  }

  /* truncate string */
  strncpy(ptr_ainfo->lastname, lastname, 255);
  (ptr_ainfo->lastname)[255] = '\0';
  return ptr_ainfo->lastname;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  set_authorinfo_firstname(): sets the firstname member variable to a new value
                         the firstname will be cropped if too long

  char* set_authorinfo_firstname returns a ptr to the firstname member variable
                         or NULL if at least one of the arguments is
			 NULL

  struct AUTHOR_INFO* ptr_ainfo ptr to authorinfo structure

  const char* firstname ptr to string with the firstname

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* set_authorinfo_firstname(struct AUTHOR_INFO* ptr_ainfo, const char* firstname) {
  if (!ptr_ainfo || !firstname) {
    return NULL;
  }

  /* truncate string */
  strncpy(ptr_ainfo->firstname, firstname, 255);
  (ptr_ainfo->firstname)[255] = '\0';

  if ((ptr_ainfo->firstname)[1] == '.') {
    (ptr_ainfo->firstname)[1] = '\0';
  }

  return ptr_ainfo->firstname;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  add_authorinfo_middlename(): adds the provided middle name to the
                         existing middlename member variable
                         the middlename will be cropped if too long

  char* set_authorinfo_middlename returns a ptr to the middlename
                         member variable or NULL if at least one of the
			 arguments is NULL

  struct AUTHOR_INFO* ptr_ainfo ptr to authorinfo structure

  const char* middlename ptr to string with the middlename

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* add_authorinfo_middlename(struct AUTHOR_INFO* ptr_ainfo, const char* middlename) {
  if (!ptr_ainfo || !middlename) {
    return NULL;
  }

  /* pool all middlenames in a single string, separated by spaces */
  if (*(ptr_ainfo->middlename)) {
    strncat(ptr_ainfo->middlename, " ", 255 - strlen(ptr_ainfo->middlename));
  }
  strncat(ptr_ainfo->middlename, middlename, 255 - strlen(ptr_ainfo->middlename));
  (ptr_ainfo->middlename)[255] = '\0';

  if (middlename[1] == '.') {
    (ptr_ainfo->middlename)[strlen(ptr_ainfo->middlename)-1] = '\0';
  }
  return ptr_ainfo->middlename;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  set_authorinfo_suffix(): sets the suffix member variable to a new value
                         the suffix will be cropped if too long

  char* set_authorinfo_suffix returns a ptr to the suffix member variable
                         or NULL if at least one of the arguments is
			 NULL

  struct AUTHOR_INFO* ptr_ainfo ptr to authorinfo structure

  const char* suffix ptr to string with the suffix

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* set_authorinfo_suffix(struct AUTHOR_INFO* ptr_ainfo, const char* suffix) {
  if (!ptr_ainfo || !suffix) {
    return NULL;
  }

  /* truncate string */
  strncpy(ptr_ainfo->suffix, suffix, 255);
  (ptr_ainfo->suffix)[255] = '\0';
  return ptr_ainfo->suffix;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  set_authorinfo_role(): sets the role member variable to a new value
                         the role will be cropped if too long

  char* set_authorinfo_role returns a ptr to the role member variable
                         or NULL if at least one of the arguments is
			 NULL

  struct AUTHOR_INFO* ptr_ainfo ptr to authorinfo structure

  const char* role ptr to string with the role

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* set_authorinfo_role(struct AUTHOR_INFO* ptr_ainfo, const char* role) {
  if (!ptr_ainfo) {
    return NULL;
  }

  if (role) {
    /* truncate string */
    strncpy(ptr_ainfo->role, role, 64);
    (ptr_ainfo->role)[63] = '\0';
  }
  else {
    *(ptr_ainfo->role) = '\0';
  }
  
  return ptr_ainfo->role;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  free_authorinfo(): frees the memory allocated for the object
                     It is safe to call this function with a NULL ptr

  void free_authorinfo returns nothing

  struct AUTHOR_INFO* ptr_ainfo ptr to authorinfo structure

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void free_authorinfo(struct AUTHOR_INFO* ptr_ainfo) {
  if (ptr_ainfo) {
    free(ptr_ainfo);
  }
}
