/*
 * The Cryptonit security software suite is developped by IDEALX
 * Cryptonit Team (http://IDEALX.org/ and http://cryptonit.org).
 *
 * Copyright 2003-2006 IDEALX
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 as published by the Free Software Foundation.
 * 
 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301, USA. 
 *
 * In addition, as two special exceptions:
 *
 * 1) IDEALX S.A.S gives permission to:
 *  * link the code of portions of his program with the OpenSSL library under
 *    certain conditions described in each source file
 *  * distribute linked combinations including the two, with respect to the
 *    OpenSSL license and with the GPL
 *
 * You must obey the GNU General Public License in all respects for all of the
 * code used other than OpenSSL. If you modify file(s) with this exception,
 * you may extend this exception to your version of the file(s), but you are
 * not obligated to do so. If you do not wish to do so, delete this exception
 * statement from your version, in all files (this very one along with all
 * source files).

 * 2) IDEALX S.A.S acknowledges that portions of his sourcecode uses (by the
 * way of headers inclusion) some work published by 'RSA Security Inc.'. Those
 * portions are "derived from the RSA Security Inc. PKCS #11Cryptographic
 * Token Interface (Cryptoki)" as described in each individual source file.
 */

#include "Dn.hh"

using std::endl;

namespace Cryptonit {
  rdn::rdn ()
    :ne(NULL)
  {}

  rdn::rdn(const rdn &n)
  {
    ne = X509_NAME_ENTRY_dup(n.ne);
  }

  rdn::rdn(X509_NAME_ENTRY *n)
  {
    ne = X509_NAME_ENTRY_dup(n);
  }

  rdn::~rdn()
  {
    this->free();
  }

  void rdn::free()
  {
    if(ne)
      {
	X509_NAME_ENTRY_free(ne);
	ne = NULL;
      }
  }

  std::string rdn::getShortName() const
  {
    int n;
    const char *s;
    if (((n = OBJ_obj2nid(ne->object)) == NID_undef) ||
	((s = OBJ_nid2sn(n)) == NULL))
      return getOID();
    else
      return s;
  }

  std::string rdn::getLongName() const
  {
    int n;
    const char *s;
    if (((n = OBJ_obj2nid(ne->object)) == NID_undef) ||
	((s = OBJ_nid2ln(n)) == NULL))
      return getShortName();
    else
      return s;
  }

  std::string rdn::getOID() const
  {
    
    char buf[128];
    OBJ_obj2txt(buf, sizeof(buf), ne->object, 1);
    return buf;
    
  }

  std::string rdn::getValue () const
  {
    return (char *)ne->value->data;
  }

  std::string rdn::getInfos() const
  {
    std::string ret;
    ret += getLongName();
    ret += " ( " + getOID();
    ret += " ) " + getShortName();
    ret += " : " + getValue() ;
    return ret;
  }

  std::string rdn::getInfosList() const
  {
    std::string ret;
    ret += getLongName();
    //ret += " ( " + getOID();
    ret += " (" + getShortName();
    ret += ") : " + getValue() ;

    return ret;
  }



  std::ostream& operator<< (std::ostream& cout, rdn& r)
  {
    
    cout << r.getLongName();
    cout << " ( " << r.getOID();
    cout << " ) " << r.getShortName();
    cout << " : " << r.getValue() ;
    
    return cout;
  }

  /**************
   * La classe dn
   * ***********/

  dn::dn ()
    :name(NULL)
  {}

  dn::dn (const dn &d)    
  {
    copy(d.rdns.begin(), d.rdns.end(), rdns.begin());
    name=X509_NAME_dup(d.name);
  }

  dn::dn (X509_NAME *n)
    :name(NULL)
  {
    int i, j = sk_X509_NAME_ENTRY_num(n->entries);
    for (i = 0; i < j; i++)
      rdns.push_back(rdn(sk_X509_NAME_ENTRY_value(n->entries,i)));
    name=X509_NAME_dup(n);
  }

  dn::~dn()
  {
    this->free();
  }

  const std::list<rdn> &dn::getDN()
  {
    return rdns;
  }

  void dn::free()
  {
    rdns.clear();
    if(name!=NULL)
      {
	X509_NAME_free(name); 
	name=NULL;
      }

  }

  std::string dn::getInfos() const
  {
    std::string ret;
    std::list<rdn>::iterator j;
    std::list<rdn> l=rdns;
    for(j = l.begin(); j != l.end(); j++)
      ret += " - " + j->getInfos() + "\n";
    return ret;
  }


   const std::vector<std::string> dn::getInfosList() const {
      std::vector<std::string> infoList;
    
    printf("entree dans la fonction getInfosList\n");

    std::list<rdn>::iterator j;
    std::list<rdn> l = rdns;

    for(j = l.begin(); j != l.end(); j++)
    {
       printf("les infos de rdn  %s\n", j->getInfos().c_str());
       infoList.push_back(j->getInfos());
       printf(" test sur le vecteur : %s\n",j->getInfosList().c_str());
    }
    return infoList;
  }


   const std::vector<std::string> dn::getInfosList(std::vector<std::string> infoList) 
      const {

    
    printf("entree dans la fonction getInfosList\n");

    std::list<rdn>::iterator j;
    std::list<rdn> l = rdns;

    for(j = l.begin(); j != l.end(); j++)
    {
       printf("les infos de rdn  %s\n", j->getInfos().c_str());
       infoList.push_back(j->getInfos());
       printf(" test sur le vecteur : %s\n",j->getInfosList().c_str());
    }
    return infoList;
  }



  std::string dn::getValue(const std::string &shortName)
  {
    std::list<rdn>::iterator j;
    for(j = rdns.begin(); j != rdns.end(); j++)
      if(j->getShortName()==shortName)
	return j->getValue();
    return std::string("");
  }


  std::string dn::getValues(int mask, char separator, char sub){
  std::string ret="";
    std::list<rdn>::iterator j;
    for(j = rdns.begin(); j != rdns.end(); ){

      if(mask & DN_DISPLAY_LONG) {
	ret+=j->getLongName();
	ret+="=";
      }
      

      if(mask & DN_DISPLAY_SHORT){
	ret+=j->getShortName();
	ret+= "=";
      }
      
      
      if(mask & DN_DISPLAY_VALUE){
	ret+=j->getValue();
      }
      if(++j !=rdns.end()) ret+=separator;
    }

    return ret;
  }
  
  
    const std::vector<std::string> dn::getValuesVect(int mask, std::string separator){

	std::vector<std::string> vect;
	std::string ret;
	std::list<rdn>::iterator j;
	
	for(j = rdns.begin(); j != rdns.end(); j++){
	    ret = "";
	    if(mask & DN_DISPLAY_LONG) {
		ret+=j->getLongName();
		ret+=separator;
	    }
	    
	    
	    if(mask & DN_DISPLAY_SHORT){
		ret+=j->getShortName();
		ret+=separator;
	    }
	    
	    
	    if(mask & DN_DISPLAY_VALUE){
		ret+=j->getValue();
	    }
	    
	    vect.push_back(ret);
	}
	
	return vect;
    }



  

  X509_NAME *dn::getX509Name(){
      return name;
  }

    bool dn::compare(dn &dnb){
	if(!name) return 0;
	return (X509_NAME_cmp(name , dnb.name)==0);
    }



//   int dn::compare(dn &dnb)
//   {
//      int res = 0;
     
// //      if(dnb == NULL)
// // 	 {
// // 	     printf("Dn->compare : parametre NULL\n");
// // 	     return false;
// // 	 }
     
//      if(!name)
// 	 {
// 	     printf("name == NULL\n");
// 	     return -1;
// 	 }
     
//      else
// 	 { 
// 	     const X509_NAME *n;
// 	     n= dnb.getX509Name();
	     
// 	     if(n != NULL){
// 		 printf("comparaison en cours ... \n");
// 		 return( X509_NAME_cmp(name, n))  ;
// 	     }
// 	     else 
 // 		 std::cout << dnb << " -->NULL" <<std::endl;
// 	 }
	     
//      printf("Sortie de compare\n");
     
//      return -1;
//   }


  
  std::ostream& operator<< (std::ostream& cout, dn& d)
  {
    std::list<rdn>::iterator j;
    for(j = d.rdns.begin(); j != d.rdns.end(); j++)
      cout << "\t" << *j << endl;
    return cout;
  }
}
