/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard street, Cambridge, MA 02139 USA
   
   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., 51 Franklin Street, Fifth Floor, Boston, MA 
   02110-1301 USA

*/

/* The original version of this file was written by Jörg Reichardt 
   The original copyright notice follows here */

/***************************************************************************
                          NetDataTypes.cpp  -  description
                             -------------------
    begin                : Mon Oct 6 2003
    copyright            : (C) 2003 by Joerg Reichardt
    email                : reichardt@mitte
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include "NetDataTypes.h"

//#################################################################################
//###############################################################################
//Constructor
NNode::NNode(unsigned long ind, unsigned long c_ind, DLList<NLink*> *ll, char* n, int states)
{
   index=ind;
   cluster_index=c_ind;
   neighbours = new DLList<NNode*>();
   n_links = new DLList<NLink*>();
   global_link_list=ll;
   strcpy(name,n);
   color.red=0;
   color.green=0;
   color.blue=0;
   strcpy(color.pajek_c,"Green");
   clustering=0.0;
   marker=0;
   affiliations=0;
   weight=0.0;
   affinity=0.0;
   distance=0;
   max_states=states;
   state_history=new unsigned long[states+1];
}

//Destructor
NNode::~NNode()
{
  Disconnect_From_All();
  delete neighbours;
  delete n_links;
  delete [] state_history;
  neighbours=NULL;
  n_links=NULL;
  state_history=NULL;
}

void NNode::Add_StateHistory(unsigned int state)
{
  if (max_states>=state) {
    state_history[state]++;
  }
}

void NNode::Set_Color(RGBcolor c)
{
  color.red=c.red; color.blue=c.blue; color.green=c.green;
  strcpy(color.pajek_c,c.pajek_c);
}

int NNode::Connect_To(NNode* neighbour, double weight)
{
  NLink *link;
  //sollen doppelte Links erlaubt sein??  NEIN
  if (!neighbour) return 0;
  if (!(neighbours->Is_In_List(neighbour)) && (neighbour!=this))
    {
      neighbours->Push(neighbour);        // nachbar hier eintragen
      neighbour->neighbours->Push(this); // diesen knoten beim nachbarn eintragen

      link=new NLink(this,neighbour, weight);        //link erzeugen
      global_link_list->Push(link);                        // in globaler liste eintragen
      n_links->Push(link);                                   // bei diesem Knoten eintragen
      neighbour->n_links->Push(link);                  // beim nachbarn eintragen

      return(1);
    }
   return(0);
}

NLink *NNode::Get_LinkToNeighbour(NNode* neighbour)
{
  DLList_Iter<NLink*> iter;
  NLink *l_cur, *link=0;
  bool found=false;
  // finde einen bestimmten Link aus der Liste der links eines Knotens
  l_cur=iter.First(n_links);
  while (!iter.End() && !found)
  {
    if (((l_cur->Get_Start()==this) && (l_cur->Get_End()==neighbour)) || ((l_cur->Get_End()==this) && (l_cur->Get_Start()==neighbour)))
    {
      found=true;
      link=l_cur;
    }
    l_cur=iter.Next();
  }
  if (found) return link; else return NULL;
}

int NNode::Disconnect_From(NNode* neighbour)
{
  //sollen doppelte Links erlaubt sein??  s.o.
  if (!neighbours) return 0;
  neighbours->fDelete(neighbour);
  n_links->fDelete(Get_LinkToNeighbour(neighbour));
  neighbour->n_links->fDelete(neighbour->Get_LinkToNeighbour(this));
  neighbour->neighbours->fDelete(this);
  return 1;
}

int NNode::Disconnect_From_All()
{
 int number_of_neighbours=0;
 while (neighbours->Size()) {
      Disconnect_From(neighbours->Pop());
      number_of_neighbours++;
 }
 return(number_of_neighbours) ;
}

/*
int NNode::Disconnect_From_All_Grandchildren()
{
 int n_l=links->Size();
 unsigned long pos=0;
 while ((n_l--)>1) {  //alle bis auf das erste loeschen
      pos=(links->Get(n_l+1))->links->Is_In_List(this);
     // printf("%d %d\n",n_l,pos);
      (links->Get(n_l+1))->links->Delete(pos);
  }
 return(pos) ;
}
*/

double NNode::Get_Links_Among_Neigbours(void)
{
//  long neighbours1, neighbours2;
  double lam=0;
  DLList_Iter<NNode*> iter1, iter2;
//  neighbours1=neighbours->Size();        //so viele Nachbarn hat die Betrachtete Node
  NNode *step1,*step2;
  step1=iter1.First(neighbours);
  while (!iter1.End()) //  for (int n1=1;n1<=neighbours1; n1++)
  {
    //step1=neighbours->Get(n1);
    //neighbours2=step1->neighbours->Size();  //so viele Nachbarn hat der n1-ste Nachbar
    step2=iter2.First(step1->Get_Neighbours());
    while (!iter2.End()) //for (int n2=1;n2<=neighbours2; n2++)
    {
        //step2=step1->neighbours->Get(n2);
        if (step2->Get_Neighbours()->Is_In_List(this)) {lam++;}
        step2=iter2.Next();
    }
  step1=iter1.Next();
  }
  return(lam/2.0);
}


double NNode::Get_Clustering()
{
  double c;
  unsigned long k;
  k=neighbours->Size();
  if (k<=1) return(0);
  c=2.0*Get_Links_Among_Neigbours()/double(k*k-k);
  return(c);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++

//Constructor
NLink::NLink(NNode *s, NNode *e, double w)
{
   start=s;
   end=e;
   weight=w;
   old_weight=0;
   marker=0;
}

//Destructor
NLink::~NLink()
{
  if (start && end) start->Disconnect_From(end);
}
