/**
	address.cpp

	Address book example XML data binding application.

	Illustrates the gSOAP XML data binding with wsdl2h and soappcp2.

	Copyright (C) 2000-2015 Robert A. van Engelen. All Rights Reserved.

	Project Source Files
	- address.xsd		Address book
	- address.cpp		Address book app (reads/writes address.xml file)
	- addresstypemap.dat	Schema namespace prefix name preference

	Generated Files
	- address.h		gSOAP data binding definitions from address.xsd
	- addressStub.h		C++ data binding definitions
	- addressH.h		Serializers
	- addressC.cpp		Serializers
	- a.nsmap		XML namespace mapping file (binds 'a' URI)
	- address.xml		Address book data generated by address app

	Build:
	> wsdl2h -g -t addresstypemap.dat address.xsd
	> soapcpp2 -2 -CS -I../../import -p address address.h
	> c++ -I../.. address.cpp addressC.cpp -o address ../../stdsoap2.cpp

	Run:
	> ./address
*/
/*
--------------------------------------------------------------------------------
gSOAP XML Web services tools
Copyright (C) 2000-2015, Robert van Engelen, Genivia, Inc. All Rights Reserved.
This software is released under one of the following two licenses:
GPL or Genivia's license for commercial use.
--------------------------------------------------------------------------------
GPL license.

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, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA

Author contact information:
engelen@genivia.com / engelen@acm.org
--------------------------------------------------------------------------------
A commercial use license is available from Genivia, Inc., contact@genivia.com
--------------------------------------------------------------------------------
*/

int main();

#include <iostream>
#include <fstream>

#include "addressH.h"	// generated, also includes stdsoap2.h
#include "a.nsmap"	// generated

/**
@fn char *user_input(const char *prompt)
@brief A quick-and-dirty user input function: reads string from stdin (up to 80
chars), trims leading and trailing blanks, and returns it
@param prompt displays prompt to user
@return string input
*/
char *user_input(const char *prompt);

/**
@brief Address book application: reads address.xml, displays its content,
prompts the user for new contact, adds it, and saves the updated address.xml.
*/
int main()
{
  // New soap struct engine context
  // Use strict validation and indented canonicalized output
  struct soap *soap = soap_new1(SOAP_XML_STRICT | SOAP_XML_INDENT | SOAP_XML_NOTYPE);

  _a__address_book *ab = soap_new__a__address_book(soap, -1);

  std::fstream fs;

  // Read the address book from address.xml (defined by address.xsd)
  fs.open("address.xml", std::ios::in);
  if (fs)
  {
    soap->is = &fs;
    if (soap_read__a__address_book(soap, ab) != SOAP_OK)
    { 
      std::cerr << "Error reading address.xml file" << std::endl;
      soap_stream_fault(soap, std::cerr);
      exit(1);
    }
    fs.close();
  }

  // Display the address book content
  std::cout << std::endl << "ADDRESS BOOK - An Example XML Data Binding Application" << std::endl << std::endl;
  for (std::vector<a__address*>::const_iterator i = ab->address.begin(); i != ab->address.end(); ++i)
  {
    if (*i)
    {
      std::cout << "Address entry " << (*i)->ID << std::endl;
      std::cout << "Name:    " << (*i)->name << std::endl;
      std::cout << "Street:  " << (*i)->street << std::endl;
      std::cout << "City:    " << (*i)->city << std::endl;
      std::cout << "Zip:     " << (*i)->zip << std::endl;
      // Advanced level: we use the soapcpp2-generated soap_a__ISO_country2s()
      // function to convert enum a__ISO_country values to strings. The strings
      // are allocated in the gSOAP engine and deleted with soap_end()
      std::cout << "Country: " << soap_a__ISO_country2s(soap, (*i)->country) <<
      std::endl;
      if ((*i)->phone)
        std::cout << "Phone:   " << *(*i)->phone << std::endl;
      if ((*i)->mobile)
        std::cout << "Mobile:  " << *(*i)->mobile << std::endl;
      // Advanced level: use the soap_dateTime2s() from the stdsoap2.cpp engine
      if ((*i)->dob)
        std::cout << "DOB:     " << soap_dateTime2s(soap, *(*i)->dob) << std::endl;
      std::cout << "---------" << std::endl;
    }
  }

  // Allocate a new address in the gSOAP engine's data space
  a__address *a = soap_new_a__address(soap, -1);
  // Set object's default values (soap_default is generated)
  a->soap_default(soap);

  a->ID = ab->address.size() + 1;

  std::cout << "Enter a new contact:" << std::endl;
  a->name = user_input("Name");
  a->street = user_input("Street");
  a->city = user_input("City");
  a->zip = user_input("Zip");
  char *s;
  do {
    s = user_input("Country");
    // Advanced level: use the generated s2a__ISO_country() to convert string to
    // enum constant
    soap->error = SOAP_OK;
    if (soap_s2a__ISO_country(soap, s, &a->country) != SOAP_OK)
      std::cerr << "Not a valid country code" << std::endl;
  }
  while (soap->error);
  if (*(s = user_input("Phone")))
  {
    // Allocate string in engine's data space:
    a->phone = soap_new_std__string(soap, -1);
    *a->phone = s;
  } 
  if (*(s = user_input("Mobile")))
  {
    // Allocate string in engine's data space:
    a->mobile = soap_new_std__string(soap, -1);
    *a->mobile = s;
  } 
  // change soap_s2dateTime to soap_xsd__dateTime when overriding the default xsd:dateTime to time_t mapping
  if (*(s = user_input("DOB")))
    if (soap_s2dateTime(soap, s, a->dob) != SOAP_OK)
      std::cerr << "Not a valid ISO 8601 date time (ignored)" << std::endl;
  soap->error = SOAP_OK;

  // Add contact to address book
  ab->address.push_back(a);

  std::cout << std::endl << "Contact information added." << std::endl;

  // Save updated address book to address.xml
  fs.open("address.xml", std::ios::out);
  if (!fs)
  {
    std::cerr << "Cannot create address.xml file" << std::endl;
    exit(1);
  }
  soap->os = &fs;
  if (soap_write__a__address_book(soap, ab) != SOAP_OK)
  {
    std::cerr << "Error writing address.xml file" << std::endl;
    soap_stream_fault(soap, std::cerr);
    exit(1);
  }
  fs.close();

  // Delete instances
  soap_destroy(soap);
  // Delete data
  soap_end(soap);
  // Free soap struct engine context
  soap_free(soap);

  return 0;
}

char *user_input(const char *prompt)
{
  static char buf[80];
  char *s;

  printf("%-9s> ", prompt);
  fgets(buf, 80, stdin);

  // Strip trailing space
  for (s = buf + strlen(buf) - 1; s > buf; s--)
  {
    if (*s > ' ')
      break;
  }
  s[1] = '\0';

  // Strip leading space
  for (s = buf; *s; s++)
  {
    if (*s > ' ')
      break;
  }

  return s;
}
