// TMS.cpp: implementation of the CTMS class.
//
//////////////////////////////////////////////////////////////////////

#include "CTMS.h"
#include <memory.h>
#include <stdio.h>
#include <memory.h>
#include <time.h>

#define TCP_BUFLEN  1024


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CTMS::CTMS( char *iniFile)
  :m_oINIFile( iniFile)
{

  //create all the clusters, start with clearing all the sizes
  memset( ClusterSize, 0, MAX_CLUSTERS * sizeof( Cluster[0]));

  //set the length for every cluster including the list of id's in the cluster
  ClusterAddItem( 0, 147, 0);
  ClusterAddItem( 0, 148, 0);
  ClusterAddItem( 0, 149, 0);
  ClusterAddItem( 0, 150, 0);
  ClusterAddItem( 0, 151, 0);
  ClusterAddItem( 0, 152, 0);
  ClusterAddItem( 0, 153, 0);
  ClusterAddItem( 0, 154, 0);
  ClusterAddItem( 0, 155, 0);
  ClusterAddItem( 0, 156, 0);
  //cluster 1
  ClusterAddItem( 1, 157, 0);
  ClusterAddItem( 1, 158, 0);
  ClusterAddItem( 1, 159, 0);
  ClusterAddItem( 1, 160, 0);
  ClusterAddItem( 1, 161, 0);
  ClusterAddItem( 1, 162, 0);
  ClusterAddItem( 1, 163, 0);
  ClusterAddItem( 1, 164, 0);
  ClusterAddItem( 1, 165, 0);
  ClusterAddItem( 1, 166, 0);
  //cluster 2
  ClusterAddItem( 2, 167, 0);
  ClusterAddItem( 2, 168, 0);
  ClusterAddItem( 2, 169, 0);
  ClusterAddItem( 2, 170, 0);
  ClusterAddItem( 2, 171, 0);
  ClusterAddItem( 2, 172, 0);
  ClusterAddItem( 2, 173, 0);
  ClusterAddItem( 2, 174, 0);
  ClusterAddItem( 2, 175, 0);
  ClusterAddItem( 2, 176, 0);
  ClusterAddItem( 2, 177, 0);
  ClusterAddItem( 2, 178, 0);
  ClusterAddItem( 2, 179, 0);
  ClusterAddItem( 2, 180, 0);
  ClusterAddItem( 2, 181, 0);
  ClusterAddItem( 2, 182, 0);
  ClusterAddItem( 2, 183, 0);
  ClusterAddItem( 2, 184, 0);
  ClusterAddItem( 2, 185, 0);
  ClusterAddItem( 2, 186, 0);
  ClusterAddItem( 2, 187, 0);
  ClusterAddItem( 2, 188, 0);
  //cluster 3
  ClusterAddItem( 3, 189, 0);
  ClusterAddItem( 3, 190, 0);
  ClusterAddItem( 3, 191, 0);
  ClusterAddItem( 3, 192, 0);
  ClusterAddItem( 3, 193, 0);
  ClusterAddItem( 3, 194, 0);
  ClusterAddItem( 3, 195, 0);
  ClusterAddItem( 3, 196, 0);
  ClusterAddItem( 3, 197, 0);
  ClusterAddItem( 3, 198, 0);
  ClusterAddItem( 3, 199, 0);
  ClusterAddItem( 3, 200, 0);
  ClusterAddItem( 3, 201, 0);
  ClusterAddItem( 3, 202, 0);
  //cluster 4
  ClusterAddItem( 4, 203, 0);
  ClusterAddItem( 4, 204, 0);
  ClusterAddItem( 4, 205, 0);
  ClusterAddItem( 4, 206, 0);
  ClusterAddItem( 4, 207, 0);
  ClusterAddItem( 4, 208, 0);
  ClusterAddItem( 4, 209, 0);
  ClusterAddItem( 4, 210, 0);
  ClusterAddItem( 4, 211, 0);
  ClusterAddItem( 4, 212, 0);
  ClusterAddItem( 4, 213, 0);
  //cluster 5
  ClusterAddItem( 5, 214, 0);
  ClusterAddItem( 5, 215, 0);
  ClusterAddItem( 5, 216, 0);
  ClusterAddItem( 5, 217, 0);
  ClusterAddItem( 5, 218, 0);
  ClusterAddItem( 5, 219, 0);
  ClusterAddItem( 5, 220, 0);
  ClusterAddItem( 5, 221, 0);
  ClusterAddItem( 5, 222, 0);
  ClusterAddItem( 5, 223, 0);
  ClusterAddItem( 5, 224, 0);
  ClusterAddItem( 5, 225, 0);
  ClusterAddItem( 5, 226, 0);
  ClusterAddItem( 5, 227, 0);
  ClusterAddItem( 5, 228, 0);
  ClusterAddItem( 5, 229, 0);
  ClusterAddItem( 5, 230, 0);
  ClusterAddItem( 5, 231, 0);
  ClusterAddItem( 5, 232, 0);
  ClusterAddItem( 5, 233, 0);
  ClusterAddItem( 5, 234, 0);
  ClusterAddItem( 5, 235, 0);
  //cluster 6
  ClusterAddItem( 6, 236, 0);
  ClusterAddItem( 6, 237, 0);
  ClusterAddItem( 6, 238, 0);
  ClusterAddItem( 6, 239, 0);
  ClusterAddItem( 6, 240, 0);
  ClusterAddItem( 6, 241, 0);
  ClusterAddItem( 6, 242, 0);
  //cluster 7
  ClusterAddItem( 7, 243, 0);
  ClusterAddItem( 7, 244, 0);
  ClusterAddItem( 7, 245, 0);
  ClusterAddItem( 7, 246, 0);
  ClusterAddItem( 7, 247, 0);
  ClusterAddItem( 7, 248, 0);
  ClusterAddItem( 7, 249, 0);
  ClusterAddItem( 7, 250, 0);
  //cluster 8
  ClusterAddItem( 8, 251, 0);
  ClusterAddItem( 8, 252, 0);
  ClusterAddItem( 8, 253, 0);
  ClusterAddItem( 8, 254, 0);
  ClusterAddItem( 8, 255, 0);
  ClusterAddItem( 8, 256, 0);
  ClusterAddItem( 8, 257, 0);
  ClusterAddItem( 8, 258, 0);
  ClusterAddItem( 8, 259, 0);
  ClusterAddItem( 8, 260, 0);
  ClusterAddItem( 8, 261, 0);
  ClusterAddItem( 8, 262, 0);
  ClusterAddItem( 8, 263, 0);
  //cluster 9
  ClusterAddItem( 9, 264, 0);
  ClusterAddItem( 9, 265, 0);
  ClusterAddItem( 9, 266, 0);
  ClusterAddItem( 9, 267, 0);
  ClusterAddItem( 9, 268, 0);
  ClusterAddItem( 9, 269, 0);
  ClusterAddItem( 9, 270, 0);
  ClusterAddItem( 9, 271, 0);
  ClusterAddItem( 9, 272, 0);
  ClusterAddItem( 9, 273, 0);
  //cluster 10
  ClusterAddItem( 10, 274, 0);
  ClusterAddItem( 10, 275, 0);
  ClusterAddItem( 10, 276, 0);
  ClusterAddItem( 10, 277, 0);
  ClusterAddItem( 10, 278, 0);
  ClusterAddItem( 10, 279, 0);
  ClusterAddItem( 10, 280, 0);
  ClusterAddItem( 10, 281, 0);
  ClusterAddItem( 10, 282, 0);
  ClusterAddItem( 10, 283, 0);
  ClusterAddItem( 10, 284, 0);
  ClusterAddItem( 10, 285, 0);
  ClusterAddItem( 10, 286, 0);
  ClusterAddItem( 10, 287, 0);
  ClusterAddItem( 10, 288, 0);
  //cluster 11
  ClusterAddItem( 11, 13, 0);
  ClusterAddItem( 11, 14, 0);
  ClusterAddItem( 11, 64, 0);
  ClusterAddItem( 11, 65, 0);
  ClusterAddItem( 11, 66, 0);
  ClusterAddItem( 11, 67, 0);
  ClusterAddItem( 11, 68, 0);
  ClusterAddItem( 11, 69, 0);
  ClusterAddItem( 11, 70, 0);
  ClusterAddItem( 11, 71, 0);
  ClusterAddItem( 11, 72, 0);
  ClusterAddItem( 11, 73, 0);
  ClusterAddItem( 11, 74, 0);
  ClusterAddItem( 11, 75, 0);
  ClusterAddItem( 11, 76, 0);
  ClusterAddItem( 11, 77, 0);
  ClusterAddItem( 11, 78, 0);
  ClusterAddItem( 11, 79, 0);
  ClusterAddItem( 11, 80, 0);
  ClusterAddItem( 11, 81, 0);
  ClusterAddItem( 11, 86, 0);
  ClusterAddItem( 11, 88, 0);
  ClusterAddItem( 11, 89, 0);
  ClusterAddItem( 11, 90, 0);
  ClusterAddItem( 11, 91, 0);
  ClusterAddItem( 11, 92, 0);
  ClusterAddItem( 11, 93, 0);
  ClusterAddItem( 11, 94, 0);
  ClusterAddItem( 11, 95, 0);
  ClusterAddItem( 11, 107, 0);
  ClusterAddItem( 11, 108, 0);
  ClusterAddItem( 11, 109, 0);
  ClusterAddItem( 11, 111, 0);
  ClusterAddItem( 11, 134, 0);
  ClusterAddItem( 11, 135, 0);
  ClusterAddItem( 11, 144, 0);
  //cluster 12
  ClusterAddItem( 12, 1, 0);
  ClusterAddItem( 12, 2, 0);
  ClusterAddItem( 12, 3, 0);
  ClusterAddItem( 12, 4, 0);
  ClusterAddItem( 12, 5, 0);
  ClusterAddItem( 12, 6, 0);
  ClusterAddItem( 12, 7, 0);
  ClusterAddItem( 12, 8, 0);
  ClusterAddItem( 12, 9, 0);
  ClusterAddItem( 12, 10, 0);
  ClusterAddItem( 12, 11, 0);
  ClusterAddItem( 12, 12, 0);
  ClusterAddItem( 12, 13, 0);
  ClusterAddItem( 12, 14, 0);
  ClusterAddItem( 12, 15, 0);
  ClusterAddItem( 12, 16, 0);
  ClusterAddItem( 12, 17, 0);
  ClusterAddItem( 12, 18, 0);
  ClusterAddItem( 12, 19, 0);
  ClusterAddItem( 12, 20, 0);
  ClusterAddItem( 12, 21, 0);
  ClusterAddItem( 12, 22, 0);
  ClusterAddItem( 12, 47, 0);
  ClusterAddItem( 12, 48, 0);
  ClusterAddItem( 12, 49, 0);
  ClusterAddItem( 12, 50, 0);
  ClusterAddItem( 12, 51, 0);
  ClusterAddItem( 12, 52, 0);
  ClusterAddItem( 12, 53, 0);
  ClusterAddItem( 12, 54, 0);
  ClusterAddItem( 12, 60, 0);
  ClusterAddItem( 12, 62, 0);
  ClusterAddItem( 12, 330, 0);
  //cluster 13
  ClusterAddItem( 13, 63, 0);
  ClusterAddItem( 13, 64, 0);
  ClusterAddItem( 13, 65, 0);
  ClusterAddItem( 13, 66, 0);
  ClusterAddItem( 13, 67, 0);
  ClusterAddItem( 13, 68, 0);
  ClusterAddItem( 13, 69, 0);
  ClusterAddItem( 13, 70, 0);
  ClusterAddItem( 13, 71, 0);
  ClusterAddItem( 13, 72, 0);
  ClusterAddItem( 13, 73, 0);
  ClusterAddItem( 13, 80, 0);
  ClusterAddItem( 13, 81, 0);
  ClusterAddItem( 13, 82, 0);
  ClusterAddItem( 13, 83, 0);
  ClusterAddItem( 13, 84, 0);
  ClusterAddItem( 13, 85, 0);
  ClusterAddItem( 13, 86, 0);
  ClusterAddItem( 13, 87, 0);
  ClusterAddItem( 13, 88, 0);
  ClusterAddItem( 13, 89, 0);
  ClusterAddItem( 13, 90, 0);
  ClusterAddItem( 13, 91, 0);
  ClusterAddItem( 13, 92, 0);
  ClusterAddItem( 13, 93, 0);
  ClusterAddItem( 13, 94, 0);
  ClusterAddItem( 13, 95, 0);
  ClusterAddItem( 13, 107, 0);
  ClusterAddItem( 13, 108, 0);
  ClusterAddItem( 13, 109, 0);
  ClusterAddItem( 13, 111, 0);
  ClusterAddItem( 13, 112, 0);
  ClusterAddItem( 13, 113, 0);
  ClusterAddItem( 13, 134, 0);
  ClusterAddItem( 13, 135, 0);
  ClusterAddItem( 13, 144, 0);
  ClusterAddItem( 13, 145, 0);
  ClusterAddItem( 13, 146, 0);
  ClusterAddItem( 13, 330, 0);
  //cluster 14
  ClusterAddItem( 14, 1, 0);
  ClusterAddItem( 14, 2, 0);
  ClusterAddItem( 14, 3, 0);
  ClusterAddItem( 14, 4, 0);
  ClusterAddItem( 14, 5, 0);
  ClusterAddItem( 14, 6, 0);
  ClusterAddItem( 14, 7, 0);
  ClusterAddItem( 14, 8, 0);
  ClusterAddItem( 14, 9, 0);
  ClusterAddItem( 14, 10, 0);
  ClusterAddItem( 14, 11, 0);
  ClusterAddItem( 14, 12, 0);
  ClusterAddItem( 14, 13, 0);
  ClusterAddItem( 14, 14, 0);
  ClusterAddItem( 14, 15, 0);
  ClusterAddItem( 14, 16, 0);
  ClusterAddItem( 14, 17, 0);
  ClusterAddItem( 14, 18, 0);
  ClusterAddItem( 14, 19, 0);
  ClusterAddItem( 14, 20, 0);
  ClusterAddItem( 14, 21, 0);
  ClusterAddItem( 14, 22, 0);
  ClusterAddItem( 14, 23, 0);
  ClusterAddItem( 14, 24, 0);
  ClusterAddItem( 14, 25, 0);
  ClusterAddItem( 14, 26, 0);
  ClusterAddItem( 14, 27, 0);
  ClusterAddItem( 14, 28, 0);
  ClusterAddItem( 14, 29, 0);
  ClusterAddItem( 14, 30, 0);
  ClusterAddItem( 14, 31, 0);
  ClusterAddItem( 14, 32, 0);
  ClusterAddItem( 14, 33, 0);
  ClusterAddItem( 14, 34, 0);
  ClusterAddItem( 14, 35, 0);
  ClusterAddItem( 14, 36, 0);
  ClusterAddItem( 14, 37, 0);
  ClusterAddItem( 14, 38, 0);
  ClusterAddItem( 14, 39, 0);
  ClusterAddItem( 14, 40, 0);
  ClusterAddItem( 14, 41, 0);
  ClusterAddItem( 14, 42, 0);
  ClusterAddItem( 14, 43, 0);
  ClusterAddItem( 14, 44, 0);
  ClusterAddItem( 14, 45, 0);
  ClusterAddItem( 14, 46, 0);
  ClusterAddItem( 14, 47, 0);
  ClusterAddItem( 14, 48, 0);
  ClusterAddItem( 14, 49, 0);
  ClusterAddItem( 14, 50, 0);
  ClusterAddItem( 14, 51, 0);
  ClusterAddItem( 14, 52, 0);
  ClusterAddItem( 14, 53, 0);
  ClusterAddItem( 14, 54, 0);
  //cluster 15
  ClusterAddItem( 15, 55, 0);
  ClusterAddItem( 15, 56, 0);
  ClusterAddItem( 15, 57, 0);
  ClusterAddItem( 15, 58, 0);
  ClusterAddItem( 15, 59, 0);
  ClusterAddItem( 15, 60, 0);
  ClusterAddItem( 15, 61, 0);
  ClusterAddItem( 15, 62, 0);
  ClusterAddItem( 15, 63, 0);
  ClusterAddItem( 15, 64, 0);
  //cluster 16
  ClusterAddItem( 16, 65, 0);
  ClusterAddItem( 16, 66, 0);
  ClusterAddItem( 16, 67, 0);
  ClusterAddItem( 16, 68, 0);
  ClusterAddItem( 16, 69, 0);
  ClusterAddItem( 16, 70, 0);
  ClusterAddItem( 16, 71, 0);
  ClusterAddItem( 16, 72, 0);
  ClusterAddItem( 16, 73, 0);
  //cluster 17
  ClusterAddItem( 17, 74, 0);
  ClusterAddItem( 17, 75, 0);
  ClusterAddItem( 17, 76, 0);
  ClusterAddItem( 17, 77, 0);
  ClusterAddItem( 17, 78, 0);
  ClusterAddItem( 17, 79, 0);
  ClusterAddItem( 17, 80, 0);
  ClusterAddItem( 17, 81, 0);
  ClusterAddItem( 17, 82, 0);
  ClusterAddItem( 17, 83, 0);
  ClusterAddItem( 17, 84, 0);
  ClusterAddItem( 17, 85, 0);
  //cluster 18
  ClusterAddItem( 18, 97, 0);
  ClusterAddItem( 18, 98, 0);
  ClusterAddItem( 18, 99, 0);
  ClusterAddItem( 18, 100, 0);
  ClusterAddItem( 18, 101, 0);
  ClusterAddItem( 18, 102, 0);
  ClusterAddItem( 18, 103, 0);
  ClusterAddItem( 18, 104, 0);
  ClusterAddItem( 18, 105, 0);
  ClusterAddItem( 18, 106, 0);
  ClusterAddItem( 18, 107, 0);
  ClusterAddItem( 18, 108, 0);
  ClusterAddItem( 18, 109, 0);
  ClusterAddItem( 18, 110, 0);
  ClusterAddItem( 18, 111, 0);
  ClusterAddItem( 18, 112, 0);
  ClusterAddItem( 18, 113, 0);
  //cluster 19
  ClusterAddItem( 19, 114, 0);
  ClusterAddItem( 19, 115, 0);
  ClusterAddItem( 19, 116, 0);
  ClusterAddItem( 19, 117, 0);
  ClusterAddItem( 19, 118, 0);
  ClusterAddItem( 19, 119, 0);
  ClusterAddItem( 19, 120, 0);
  ClusterAddItem( 19, 121, 0);
  ClusterAddItem( 19, 122, 0);
  ClusterAddItem( 19, 123, 0);
  ClusterAddItem( 19, 124, 0);
  ClusterAddItem( 19, 125, 0);
  ClusterAddItem( 19, 126, 0);
  ClusterAddItem( 19, 127, 0);
  ClusterAddItem( 19, 128, 0);
  ClusterAddItem( 19, 129, 0);
  //cluster 20
  ClusterAddItem( 20, 130, 0);
  ClusterAddItem( 20, 131, 0);
  ClusterAddItem( 20, 132, 0);
  ClusterAddItem( 20, 133, 0);
  //cluster 21
  ClusterAddItem( 21, 134, 0);
  ClusterAddItem( 21, 135, 0);
  //cluster 22
  ClusterAddItem( 22, 136, 0);
  ClusterAddItem( 22, 137, 0);
  ClusterAddItem( 22, 138, 0);
  ClusterAddItem( 22, 139, 0);
  ClusterAddItem( 22, 140, 0);
  ClusterAddItem( 22, 141, 0);
  ClusterAddItem( 22, 142, 0);
  ClusterAddItem( 22, 143, 0);
  //cluster 23
  ClusterAddItem( 23, 289, 0);
  ClusterAddItem( 23, 290, 0);
  ClusterAddItem( 23, 291, 0);
  ClusterAddItem( 23, 292, 0);
  ClusterAddItem( 23, 293, 0);
  ClusterAddItem( 23, 294, 0);
  ClusterAddItem( 23, 295, 0);
  ClusterAddItem( 23, 296, 0);
  ClusterAddItem( 23, 297, 0);
  ClusterAddItem( 23, 298, 0);
  ClusterAddItem( 23, 299, 0);
  ClusterAddItem( 23, 300, 0);
  ClusterAddItem( 23, 301, 0);
  ClusterAddItem( 23, 302, 0);
  ClusterAddItem( 23, 303, 0);
  ClusterAddItem( 23, 304, 0);
  ClusterAddItem( 23, 305, 0);
  ClusterAddItem( 23, 306, 0);
  ClusterAddItem( 23, 307, 0);
  ClusterAddItem( 23, 308, 0);
  ClusterAddItem( 23, 309, 0);
  ClusterAddItem( 23, 310, 0);
  ClusterAddItem( 23, 311, 0);
  ClusterAddItem( 23, 312, 0);
  ClusterAddItem( 23, 313, 0);
  ClusterAddItem( 23, 314, 0);
  ClusterAddItem( 23, 315, 0);
  ClusterAddItem( 23, 316, 0);
  ClusterAddItem( 23, 317, 0);
  ClusterAddItem( 23, 318, 0);
  ClusterAddItem( 23, 319, 0);
  ClusterAddItem( 23, 320, 0);
  ClusterAddItem( 23, 321, 0);
  ClusterAddItem( 23, 322, 0);
  ClusterAddItem( 23, 323, 0);
  ClusterAddItem( 23, 324, 0);
  ClusterAddItem( 23, 325, 0);
  ClusterAddItem( 23, 326, 0);
  ClusterAddItem( 23, 327, 0);
  ClusterAddItem( 23, 328, 0);
  ClusterAddItem( 23, 329, 0);
  ClusterAddItem( 23, 355, 0);
  ClusterAddItem( 23, 356, 0);
  ClusterAddItem( 23, 357, 0);
  ClusterAddItem( 23, 358, 0);
  ClusterAddItem( 23, 359, 0);
  ClusterAddItem( 23, 360, 0);
  ClusterAddItem( 23, 361, 0);
  ClusterAddItem( 23, 362, 0);
  //cluster 24
  ClusterAddItem( 24, 144, 0);
  //cluster 25
  ClusterAddItem( 25, 145, 0);
  ClusterAddItem( 25, 146, 0);
  //cluster 26
  ClusterAddItem( 26, 86, 0);
  ClusterAddItem( 26, 87, 0);
  ClusterAddItem( 26, 88, 0);
  ClusterAddItem( 26, 89, 0);
  ClusterAddItem( 26, 90, 0);
  ClusterAddItem( 26, 91, 0);
  ClusterAddItem( 26, 92, 0);
  ClusterAddItem( 26, 93, 0);
  ClusterAddItem( 26, 94, 0);
  ClusterAddItem( 26, 95, 0);
  ClusterAddItem( 26, 96, 0);
  //cluster 40
  ClusterAddItem( 40, 96, 0);
  ClusterAddItem( 40, 330, 0);
  ClusterAddItem( 40, 335, 0);
  ClusterAddItem( 40, 336, 0);
  ClusterAddItem( 40, 151, 0);
  ClusterAddItem( 40, 72, 0);
  ClusterAddItem( 40, 73, 0);
  ClusterAddItem( 40, 63, 0);
  ClusterAddItem( 40, 64, 0);
  ClusterAddItem( 40, 87, 0);
  ClusterAddItem( 40, 331, 0);
  ClusterAddItem( 40, 337, 0);
  ClusterAddItem( 40, 338, 0);
  ClusterAddItem( 40, 332, 0);
  ClusterAddItem( 40, 339, 0);
  ClusterAddItem( 40, 340, 0);
  ClusterAddItem( 40, 333, 0);
  ClusterAddItem( 40, 341, 0);
  ClusterAddItem( 40, 342, 0);
  ClusterAddItem( 40, 110, 0);
  ClusterAddItem( 40, 334, 0);
  ClusterAddItem( 40, 343, 0);
  ClusterAddItem( 40, 344, 0);
  ClusterAddItem( 40, 345, 0);
  ClusterAddItem( 40, 144, 0);

  //cluster 41
  ClusterAddItem( 41, 136, 0);
  ClusterAddItem( 41, 137, 0);
  ClusterAddItem( 41, 138, 0);
  ClusterAddItem( 41, 139, 0);
  ClusterAddItem( 41, 140, 0);
  ClusterAddItem( 41, 141, 0);
  ClusterAddItem( 41, 142, 0);
  ClusterAddItem( 41, 143, 0);
  //cluster 42
  ClusterAddItem( 42, 145, 0);
  ClusterAddItem( 42, 146, 0);
  //cluster 43
  ClusterAddItem( 43, 289, 0);
  ClusterAddItem( 43, 290, 0);
  ClusterAddItem( 43, 291, 0);
  ClusterAddItem( 43, 292, 0);
  ClusterAddItem( 43, 293, 0);
  ClusterAddItem( 43, 294, 0);
  ClusterAddItem( 43, 295, 0);
  ClusterAddItem( 43, 296, 0);
  ClusterAddItem( 43, 297, 0);
  ClusterAddItem( 43, 298, 0);
  ClusterAddItem( 43, 299, 0);
  ClusterAddItem( 43, 300, 0);
  ClusterAddItem( 43, 301, 0);
  ClusterAddItem( 43, 302, 0);
  ClusterAddItem( 43, 303, 0);
  ClusterAddItem( 43, 304, 0);
  ClusterAddItem( 43, 305, 0);
  ClusterAddItem( 43, 306, 0);
  ClusterAddItem( 43, 307, 0);
  ClusterAddItem( 43, 308, 0);
  ClusterAddItem( 43, 309, 0);
  ClusterAddItem( 43, 310, 0);
  ClusterAddItem( 43, 311, 0);
  ClusterAddItem( 43, 312, 0);
  ClusterAddItem( 43, 313, 0);
  ClusterAddItem( 43, 314, 0);
  ClusterAddItem( 43, 315, 0);
  ClusterAddItem( 43, 316, 0);
  ClusterAddItem( 43, 317, 0);
  ClusterAddItem( 43, 318, 0);
  ClusterAddItem( 43, 319, 0);
  ClusterAddItem( 43, 320, 0);
  ClusterAddItem( 43, 321, 0);
  ClusterAddItem( 43, 322, 0);
  ClusterAddItem( 43, 323, 0);
  ClusterAddItem( 43, 324, 0);
  ClusterAddItem( 43, 325, 0);
  ClusterAddItem( 43, 326, 0);
  ClusterAddItem( 43, 327, 0);
  ClusterAddItem( 43, 328, 0);
  ClusterAddItem( 43, 329, 0);
  ClusterAddItem( 43, 355, 0);
  ClusterAddItem( 43, 356, 0);
  ClusterAddItem( 43, 357, 0);
  ClusterAddItem( 43, 358, 0);
  ClusterAddItem( 43, 359, 0);
  ClusterAddItem( 43, 360, 0);
  ClusterAddItem( 43, 361, 0);
  ClusterAddItem( 43, 362, 0);
  //cluster 44
  ClusterAddItem( 44, 144, 0);
  //cluster 45
  ClusterAddItem( 45, 151, 0);
  ClusterAddItem( 45, 72, 0);
  ClusterAddItem( 45, 73, 0);
  ClusterAddItem( 45, 63, 0);
  ClusterAddItem( 45, 64, 0);
  ClusterAddItem( 45, 87, 0);
  //cluster 46
  ClusterAddItem( 46, 351, 0);
  ClusterAddItem( 46, 350, 0);
  ClusterAddItem( 46, 352, 0);
  ClusterAddItem( 46, 346, 0);
  ClusterAddItem( 46, 347, 0);
  //cluster 47
  ClusterAddItem( 47, 348, 0);
  ClusterAddItem( 47, 349, 0);

  int i;

  for (i = 0; i < MAX_PORT; i++)
  {
    m_iBufferLength[ i] = 0;
    m_iBufferLength[ MAX_PORT + i] = 0;

    m_iPortCount[ i] = 0;
    m_iPortCount[ MAX_PORT + i] = 0;
  }

  //read the timeout value for CTMS connection retries
  m_iRetryTimeout = m_oINIFile.GetInteger( "RetryTime", "CTMS", DEF_RETRYTIMEOUT);
  m_iTimer[ 0] = m_iTimer[ 1] = 1;
  m_sClock[ 0] = m_sClock[ 1] = 0;

  //start with no connection
  m_iConnected[ CTMS_REMOTE] = m_iConnected[ CTMS_LOCAL] = 0;
  m_iRestart[ CTMS_REMOTE] = m_iRestart[ CTMS_LOCAL] = 0;

  //reset data packet counter
  m_iCount = 0;
  m_iStatusHist[ 0] = m_iStatusHist[ 1] = 0;
  m_iStorigsmeldingenOld = 0;
  m_iStatusmeldingenOld = 0;
  m_iVolgnr_MeetperiodeOld = 0;

  //all sockets are invalid
  for (i = 0; i < 2*MAX_SOCK; i++)
    m_sSocket[ i] = INVALID_SOCKET;

  //creasrte semaphores
  m_hSemaphore[ CTMS_REMOTE] = CreateSemaphore( NULL, 1, 1, NULL);
  m_hSemaphore[ CTMS_LOCAL]  = CreateSemaphore( NULL, 1, 1, NULL);

  //reset the internal connection state
  m_iConnectionState[ CTMS_REMOTE] = 0;
  m_iConnectionState[ CTMS_LOCAL]  = 0;

  //create a socket
  m_wTDIAddress.sin_family = AF_INET;
  m_wTDIAddress.sin_addr.s_addr = INADDR_ANY;
  m_wTDIAddress.sin_port = htons( 0);

  m_wRemoteAddress.sin_family = AF_INET;
  m_wRemoteAddress.sin_addr.s_addr = INADDR_ANY;
  m_wRemoteAddress.sin_port = htons( 0);
  m_wLocalAddress.sin_family = AF_INET;
  m_wLocalAddress.sin_addr.s_addr = INADDR_ANY;
  m_wLocalAddress.sin_port = htons( 0);

  //get the local and remote IP address
  m_wRemoteAddress.sin_addr.S_un.S_addr = inet_addr ( m_oINIFile.GetString( "IPCTMSRemote", "CTMS", "192.1.1.1"));
  m_wLocalAddress.sin_addr.S_un.S_addr = inet_addr ( m_oINIFile.GetString( "IPCTMSLocal", "CTMS", "192.1.1.2"));

  //start using Winsock...
  WSADATA wsaData;
  WSAStartup ( MAKEWORD ( 2,2 ), &wsaData );
  GetHostAddress();
}


//////////////////////////////////////////////////////////////////////
// Destruction
//////////////////////////////////////////////////////////////////////
CTMS::~CTMS()
{

  int i;


  //disconnect all sockets
  for (i = 0; i < 2*MAX_SOCK; i++)
    DeleteSocket( i);

  //cleanup WinSock interface
  //WSACleanup();
}


//////////////////////////////////////////////////////////////////////
// Add item to a user defined cluster
//////////////////////////////////////////////////////////////////////
void CTMS::ClusterAddItem(int Idx, short Item, int User)
{

  //check if cluster index is in user defined range
  if (User)
    if ((Idx < CLUSTER_USER_MIN) || (Idx > CLUSTER_USER_MAX)) return;

  //check if item is in range
  if ((Item < PARAMETER_MIN) || (Item >= CTMS_PARAMETER_MAX)) return;

  //add the item, if there is a free position
  if (ClusterSize[ Idx] < MAX_CLUSTER_ITEM) 
    Cluster[ Idx][ ClusterSize[ Idx]++] = Item;
}

//////////////////////////////////////////////////////////////////////
// Return the actual size of the cluster
//////////////////////////////////////////////////////////////////////
int CTMS::ClusterGetSize(int Idx)
{

  //check cluster numer
  if ((Idx < 0) || (Idx >= MAX_CLUSTERS)) return 0;

  return ClusterSize[ Idx];
}

//////////////////////////////////////////////////////////////////////
// Remove item from a user defined cluster
//////////////////////////////////////////////////////////////////////
void CTMS::ClusterRemoveItem(int Idx, short Item)
{

  int i;


  //check if cluster index is in user defined range
  if ((Idx < CLUSTER_USER_MIN) || (Idx > CLUSTER_USER_MAX)) return;

  //check if item is in range
  if ((Item < PARAMETER_MIN) || (Item >= CTMS_PARAMETER_MAX)) return;

  //search for the item number
  for (i = 0; i < ClusterSize[ Idx]; i++)
  {

    //if found, remove item
    if (Item == Cluster[ Idx][ i])
    {

      //shift all remaining items
      while ((++i) < ClusterSize[ Idx])
        Cluster[ Idx][ i - 1] = Cluster[ Idx][ i];
      
      //reduce the number of items with one
      ClusterSize[ Idx]--;

      //Clear the freeed item
      Cluster[ Idx][ i] = 0;
      break; //leave for loop
    }
  }
}


//////////////////////////////////////////////////////////////////////
// Delete complete cluster from usr defined range
//////////////////////////////////////////////////////////////////////
void CTMS::ClusterDelete(int Idx)
{

  int i;


  //check if cluster index is in user defined range
  if ((Idx < CLUSTER_USER_MIN) || (Idx > CLUSTER_USER_MAX)) return;

  //clear the cluster
  for (i = 0; i < ClusterSize[ Idx]; i++)
    Cluster[ Idx][ i] = 0;

  //reduce the number of items with one
  ClusterSize[ Idx] = 0;
}


//////////////////////////////////////////////////////////////////////
// Return parameter number to user from a cluster
//////////////////////////////////////////////////////////////////////
int CTMS::ClusterGetItem(int Idx, short Offset)
{

  //Paramete rnumber 0 is not used as a parameter, and therefore 
  //returned if there i snothing else to do

  //check if cluster number is in range
  if ((Idx < 0) || (Idx >= MAX_CLUSTERS)) return 0;

  //check if itmem number is in range
  if ((Offset < 0) || (Offset>MAX_CLUSTER_ITEM))
    return 0;

  //return parameter index
  return Cluster[ Idx][ Offset];
}

/////////////////////////////////////////////////////////////////////////////
// Let user now if there is connection with the remote CTMS
/////////////////////////////////////////////////////////////////////////////
int CTMS::IsConnected( int local)
{

  return m_iConnected[ local];
}


/////////////////////////////////////////////////////////////////////////////
// Get the port number(s) for the remote CTMS
/////////////////////////////////////////////////////////////////////////////
int CTMS::GetPort(int index, int local)
{

  if ((local != 0) && (local != 1)) return 0;

  //check if index is in range
  if ((index < 0) ||(index >= MAX_PORT))
    return 0;

  //return actual port number
  if (m_iConnected[ local])
    return m_iPort[ index + (local*MAX_PORT)];
  else
    return 0;
}

/////////////////////////////////////////////////////////////////////////////
// Get the IP address of the TDI
/////////////////////////////////////////////////////////////////////////////
unsigned int CTMS::GetAddressTDI()
{

//  if (m_sSocket != INVALID_SOCKET)
//    return inet_ntoa( m_wLocalAddress.sin_addr); //S_addr
//  else return "0.0.0.0";
  return m_wTDIAddress.sin_addr.S_un.S_addr;
}


/////////////////////////////////////////////////////////////////////////////
// Get the IP address of the local CTMS
/////////////////////////////////////////////////////////////////////////////
unsigned int CTMS::GetAddressLocal()
{

  return m_wLocalAddress.sin_addr.S_un.S_addr;
}


/////////////////////////////////////////////////////////////////////////////
// Get the IP address of the remote CTMS
/////////////////////////////////////////////////////////////////////////////
unsigned int CTMS::GetAddressCTMS()
{

  return m_wRemoteAddress.sin_addr.S_un.S_addr;
}


/////////////////////////////////////////////////////////////////////////////
// Return retry timeout for connections to user
/////////////////////////////////////////////////////////////////////////////
int CTMS::GetRetryTime()
{

  return m_iRetryTimeout;
}


/////////////////////////////////////////////////////////////////////////////
// Set retry timeout for building connections
/////////////////////////////////////////////////////////////////////////////
void CTMS::SetRetryTime(int seconds)
{

  if (seconds < MIN_RETRYTIMEOUT)
    seconds = MIN_RETRYTIMEOUT;

  if (seconds > MAX_RETRYTIMEOUT)
    seconds = MAX_RETRYTIMEOUT;

  //save the new value
  m_iRetryTimeout = seconds;

  //and write to INI file
  m_oINIFile.PutInteger( m_iRetryTimeout, "RetryTime", "CTMS");
}


/////////////////////////////////////////////////////////////////////////////
// Set new IP address for remote CTMS
/////////////////////////////////////////////////////////////////////////////
void CTMS::SetAddressCTMS(int address)
{

  //save the new address
  m_wRemoteAddress.sin_addr.S_un.S_addr = address;

  //update the ini file
  m_oINIFile.PutString( inet_ntoa( m_wRemoteAddress.sin_addr), "IPCTMSRemote", "CTMS");
}


/////////////////////////////////////////////////////////////////////////////
// Set new IP address for local CTMS
/////////////////////////////////////////////////////////////////////////////
void CTMS::SetAddressLocal(int address)
{

  //save the new address
  m_wLocalAddress.sin_addr.S_un.S_addr = address;

  //update the ini file
  m_oINIFile.PutString( inet_ntoa( m_wLocalAddress.sin_addr), "IPCTMSLocal", "CTMS");
}


/////////////////////////////////////////////////////////////////////////////
// Set new connectin state of TDI with CTMS
/////////////////////////////////////////////////////////////////////////////
void CTMS::SetConnection(int connection, int local)
{

  m_iConnected[ local] = (connection) ? 1: 0;
}


/////////////////////////////////////////////////////////////////////////////
// CTMS sends data to TDI, function returns TRUE if complete message is 
// received. NOTE: buffer can be filled in more then one call!
/////////////////////////////////////////////////////////////////////////////
BOOL CTMS::Receive(unsigned char *buffer, int bufsize, int *length, SOCKET sock, int *disconnect)
{

  FD_SET rfds;
  TIMEVAL t = {0, 0};
  int x;
  int i;


  //prepare select function to get received data info
  FD_ZERO( &rfds);
  FD_SET( sock, &rfds);
  *disconnect = FALSE;

  //delete exceptional messages
  if (*length >= (bufsize - 100)) *length = 0;
  //remove the first complete message, user should have processed it
  if (buffer[ 0] == CTMS_STX)
    for (i = 0; i < *length; i++)
      if (buffer[ i] == CTMS_ETX)
      {

        //remove message
        memmove( buffer, &buffer[ i+1], bufsize - i - 1);
        *length = *length - i;
        break;
      }

  //check if there is data
  if ((x = select( 0, &rfds, NULL, NULL, &t)) == SOCKET_ERROR)
    *disconnect = TRUE;
  else
  {
    if (x)
    {

      //receive the data
      x = recv( sock, (char *)&buffer[ *length], bufsize - *length, 0);

      //disconnnect received ?
      if ((x == 0) || (x == SOCKET_ERROR))
      {

        *disconnect = TRUE;
        return FALSE;
      }

      //check for start of transmission
      for (i= *length; i < (*length + x); i++)
      {

        //check absolute message length
        if (*length >= 4)
        {

          //if we have more characters received then specified in the
          //message, disrgard it and start again
          if (*length > (buffer[3]*256 + buffer[2]))
            *length = 0;
        }

        //first character received
        if ((buffer[ i] == CTMS_STX) && (*length == 0))
        {
          //move the start of buffer
          memmove( buffer, &buffer[ i], *length+x-i);
          x = *length+x-i;
          *length = 0;
        }

        //chec for complete message
        if ((buffer[ 0] == CTMS_STX) && (buffer[ i] == CTMS_ETX))
        {

          if (i == (buffer[3]*256 + buffer[2]- 1))
          {

            //adjust length
            *length += 1;
            return TRUE;
          }
        }

        //update the actual length
        if (buffer[ 0] == CTMS_STX) *length += 1;
      }
    }
  }
  return FALSE;
}

/////////////////////////////////////////////////////////////////////////////
// TDI sends data to the CTMS, zero is returned for a success
/////////////////////////////////////////////////////////////////////////////
int CTMS::Send(unsigned char *buffer, int length, SOCKET sock)
{

  unsigned char sendbuf[ 1024];
  int           i = 0;
  int           k;
  struct        tm *t;
  long          lt;


  //read and set the actual date and time
  time( &lt);
  t = localtime( &lt);

  //update the counter
  if (++m_iCount > 0x0000ffff) m_iCount = 1;

  //fill in the header for the message
  sendbuf[ i++] = CTMS_STX;
  sendbuf[ i++] = CTMS_INVSTX;

  //length of datapacket
  sendbuf[ i++] = LSBinShort( (short)(length+10));
  sendbuf[ i++] = MSBinShort( (short)(length+10));
//  sendbuf[ i++] = LSBinShort( (short)(length));
//  sendbuf[ i++] = MSBinShort( (short)(length));

  //datapacket counter
  sendbuf[ i++] = LSBinShort( (short)m_iCount);
  sendbuf[ i++] = MSBinShort( (short)m_iCount);

  //time
  sendbuf[ i++] = t->tm_hour;
  sendbuf[ i++] = t->tm_min;
  sendbuf[ i++] = t->tm_sec;

  //data
  for( k = 0; k < length; k++)
    sendbuf[ i++] = buffer[ k];

  //end of transmission
  sendbuf[ i++] = CTMS_ETX;

  //now do the real sending
  if (send( sock, (char *)sendbuf, i, 0) == SOCKET_ERROR)
    return -1;

  //report success  
  return 0;
}



#ifdef RLD_CTMS
/////////////////////////////////////////////////////////////////////////////
// CTMS sends data to the TDI, zero is returned for a success
/////////////////////////////////////////////////////////////////////////////
int CTMS::CTMSSend(unsigned char *buffer, int length, SOCKET sock)
{

  unsigned char sendbuf[ 1024];
  int           i = 0;
  int           k;


  //check if there is a connection with CTMS
  if (IsConnected()) return -1;

  //fill in the header for the message
  sendbuf[ i++] = CTMS_STX;
  sendbuf[ i++] = CTMS_INVSTX;

  //length of datapacket
  sendbuf[ i++] = LSBinShort( (short)(length+10));
  sendbuf[ i++] = MSBinShort( (short)(length+10));

  //data
  for( k = 0; k < length; k++)
    sendbuf[ i++] = buffer[ k];

  //end of transmission
  sendbuf[ i++] = CTMS_ETX;

  //now do the real sending
  if (send( sock, (char *)sendbuf, i, 0) == SOCKET_ERROR)
    return -1;

  //report success  
  return 0;
}
#endif

//////////////////////////////////////////////////////////////////////
// Start timer
//////////////////////////////////////////////////////////////////////
void CTMS::StartTimer(int idx)
{

  //start the timer
  if( !m_iTimer[ idx])
//  {
    m_lTime[ idx] = clock();
//    m_lEndTime[ idx] = m_lTime[ idx] + (CLOCKS_PER_SEC * m_iRetryTimeout);
//  }
}

//////////////////////////////////////////////////////////////////////
// Check if timer has elapsed
//////////////////////////////////////////////////////////////////////
int CTMS::ElapsedTimer( int idx)
{

  clock_t t = clock();
  int     temp = 0;


  //check if timer has elapsed
  if( !m_iTimer[ idx])
  {

    if (t > (m_lTime[ idx] + (CLOCKS_PER_SEC * m_iRetryTimeout)))
      return (m_iTimer[ idx] = 1);
    else
      if (t < m_lTime[ idx])
        StartTimer( idx);
  }
  else
  {
    m_iTimer[ idx] = 0;
    StartTimer( idx);
  }

  return 0;
}

/////////////////////////////////////////////////////////////////////////////
// Connect to CTMS, first sends connect, then waits for portnumbers.
// In hte end four connections will be setup....
/////////////////////////////////////////////////////////////////////////////
void CTMS::Connection(int xport, int local)
{

  int i;
  FD_SET rfds;
  FD_SET wfds;
  FD_SET efds;
  TIMEVAL t = {0, 0};
  unsigned char  buf[ TCP_BUFLEN];
  int len = 0;
  int sock_idx;
  int port_idx;

  
  //check th eindex for local and or remote
  if ((local != CTMS_LOCAL) && (local != CTMS_REMOTE)) return;

  //don't do anything if there is a connection
  if (IsConnected( local)) return;
  Lock( local);

  //to setup a connection there several steps,
  //1. connect to CTMS with port number specified.
  //2. connection successfull, wait for data
  //3. check data and retreive port numbers (4) for connections
  //4. build first connection
  //5. build second connection
  //6. build third connection
  //7. build fourth connection
  switch (m_iConnectionState[ local])
  {

    /////////////////////////////////////////////
    //just wait for the retry time
    case 0:

      //time has elapsed
      if (ElapsedTimer( local))
        m_iConnectionState[ local] = 1;
      break;

    /////////////////////////////////////////////
    //connect to CTMS
    case 1:

      //get the IP address for our TDI
      if (!GetHostAddress())
      {

        //unable to retrieve host address, try again some time later
        m_iConnectionState[ local] = 3;
        break;
      }

      //make sure we have all the sockets
      for (i = local*(MAX_SOCK); i < ((local+1)*MAX_SOCK); i++)
        if (m_sSocket[ i] == INVALID_SOCKET) CreateSocket( i);
        else
        {

          DeleteSocket( i);
          CreateSocket( i);
        }

      //local we don't care about the port number
      m_wTDIAddress.sin_port = htons( (u_short)0);

      //bind the socket to the local port
      if (!(i = bind( m_sSocket[ local*(MAX_SOCK)], (SOCKADDR *)&m_wTDIAddress, sizeof( m_wTDIAddress))))
      {

        //the actual connect
        if (!local)
        {

          m_wRemoteAddress.sin_port = htons( (u_short)CTMS_REMOTE_PORT);

          //connect to remote CTMS
          if (!(i = connect( m_sSocket[ local*MAX_SOCK], (SOCKADDR *) &m_wRemoteAddress, sizeof( m_wRemoteAddress))))
            m_iConnectionState[ local] = 4;
          else
          {

            //check if connection is pending
            if (WSAGetLastError() == WSAEWOULDBLOCK) m_iConnectionState[ local] = 2;
          }
        }
        else
        {

          m_wLocalAddress.sin_port = htons( (u_short)CTMS_LOCAL_PORT);

          if (!(i = connect( m_sSocket[ local*MAX_SOCK], (SOCKADDR *) &m_wLocalAddress, sizeof( m_wLocalAddress))))
            m_iConnectionState[ local] = 4;
          else
          {

            //check if connection is pending
            if (WSAGetLastError() == WSAEWOULDBLOCK)
              m_iConnectionState[ local] = 2;
          }
        }
      }
      else m_iConnectionState[ local] = 3;

      break;

    /////////////////////////////////////////////
    // Check connection build
    case 2:

      //fill structures with sockets to observe
      FD_ZERO( &efds);
      FD_SET( m_sSocket[ local*MAX_SOCK], &efds);
      FD_ZERO( &wfds);
      FD_SET( m_sSocket[ local*MAX_SOCK], &wfds);

      //connect is pending, wait for completion
      if ((i = select( 0, NULL, &wfds, &efds, &t)) == SOCKET_ERROR)
      {

        //declare all sockets invalid
        for (i = local*MAX_SOCK; i < ((local+1)*MAX_SOCK); i++)
          DeleteSocket( i);

        //try agein
        m_iConnectionState[ local] = 0;
      }
      else
      {

        //receive the port numbers
        if (i) 
        {
        
          //connection establshed?
          if (FD_ISSET( m_sSocket[ local*MAX_SOCK], &wfds))
            m_iConnectionState[ local] = 4;

          //just disconnect all the sockets and try again    
          if (FD_ISSET( m_sSocket[ local*MAX_SOCK], &efds))
            m_iConnectionState[ local] = 3;
        }
      }
      break;

    /////////////////////////////////////////////
    //disconnect all connections and try to start again
    case 3:

      //disconnect
      for (i = local*MAX_SOCK; i < ((local+1)*MAX_SOCK); i++)
        DeleteSocket( i);

      for (i = 0; i < MAX_PORT; i++)
      {

        m_iBufferLength[ (local*MAX_PORT) + i] = 0;
        m_iPortCount[ (local*MAX_PORT) + i] = 0;
      }

      m_iConnected[ local] = 0;
      m_iConnectionState[ local] = 0;
      break;

    /////////////////////////////////////////////
    //connection present, wait for port numbers
    case 4:

      //fill structures with sockets to observe
      FD_ZERO( &rfds);
      FD_SET( m_sSocket[ local*MAX_SOCK], &rfds);

      //connect is pending, wait for completion
      if ((i = select( 0, &rfds, NULL, NULL, &t)) == SOCKET_ERROR)
        m_iConnectionState[ local] = 3;  //disconnect and try again
      else
      {

        //receive the port numbers
        if (i) //data present, there is only one socket
            m_iConnectionState[ local] = 5;
      }
      break;

    /////////////////////////////////////////////
    //read the port numbers, data is ready to receive
    case 5:

      if ((len = recv( m_sSocket[ local*MAX_SOCK], (char *)buf, BUFLEN, 0)) < (CTMS_HDR+CTMS_CONNECT+CTMS_FTR))
        m_iConnectionState[ local] = 3; //not enough data, disconnect
      else
      {

        //we have the port numbers, just save them
        for (i = 0; i < MAX_PORT; i++)
          m_iPort[ (local*MAX_PORT) + i] = ((unsigned int)buf[ CTMS_HDR+3+(2*i)] << 8) + (unsigned int)buf[ CTMS_HDR+4+(2*i)];


        //don't need the first connection anymore
        DeleteSocket( local*MAX_SOCK);

        //now we can connect all four priorities
        m_iConnectionState[ local] = 6;
      }
      break;

    /////////////////////////////////////////////
    // connect port 1
    case 6:

      //port index
      port_idx = local*MAX_PORT;

      //socket index
      sock_idx = local*(MAX_SOCK)+1+m_iPortCount[ port_idx];

      //bind the socket to the local port
      m_wTDIAddress.sin_port = htons( (u_short)0);
      i = bind( m_sSocket[ sock_idx], (SOCKADDR *)&m_wTDIAddress, sizeof( m_wTDIAddress));

      if (!i)
      {

        //the actual connect
        if (!local)
        {

          //remote port number
          m_wRemoteAddress.sin_port = htons( (u_short)m_iPort[ port_idx]);

          //connect to remote CTMS
          if (!(i = connect( m_sSocket[ sock_idx], (SOCKADDR *) &m_wRemoteAddress, sizeof( m_wRemoteAddress))))
            m_iConnectionState[ local] = 8;
          else
            //check if connection is pending
            if (WSAGetLastError() == WSAEWOULDBLOCK)
              m_iConnectionState[ local] = 7;
            else
              m_iConnectionState[ local] = 3;
        }
        else
        {

          m_wLocalAddress.sin_port = htons( (u_short)m_iPort[ port_idx]);

          if (!(i = connect( m_sSocket[ sock_idx], (SOCKADDR *) &m_wLocalAddress, sizeof( m_wLocalAddress))))
            m_iConnectionState[ local] = 8;
          else
            //check if connection is pending
            if (WSAGetLastError() == WSAEWOULDBLOCK)
              m_iConnectionState[ local] = 7;
            else
              m_iConnectionState[ local] = 3;
        }
      }
      else m_iConnectionState[ local] = 3; //try again
      break;

    /////////////////////////////////////////////
    // Check connection build 1
    case 7:

      //port index
      port_idx = local*MAX_PORT;

      //socket index
      sock_idx = local*(MAX_SOCK)+1+m_iPortCount[ port_idx];

      //fill structures with sockets to observe
      FD_ZERO( &efds);
      FD_SET( m_sSocket[ sock_idx], &efds);
      FD_ZERO( &wfds);
      FD_SET( m_sSocket[ sock_idx], &wfds);

      //connect is pending, wait for completion
      if ((i = select( 0, NULL, &wfds, &efds, &t)) == SOCKET_ERROR)
        m_iConnectionState[ local] = 3; //try again
      else
      {

        //receive the port numbers
        if (i) 
        {
        
          //connection establshed?
          if (FD_ISSET( m_sSocket[ sock_idx], &wfds))
          {

            if (m_iPortCount[ port_idx]) 
              m_iConnectionState[ local] = 8;
            else
            {

              m_iPortCount[ port_idx]++;
              m_iConnectionState[ local] = 6;
            }
          }

          //just disconnect all the sockets and try again    
          if (FD_ISSET( m_sSocket[ sock_idx], &efds))
            m_iConnectionState[ local] = 3;
        }
      }
      break;

    /////////////////////////////////////////////
    // connect port 2
    case 8:

      //port index
      port_idx = (local*MAX_PORT) + 1;

      //socket index
      sock_idx = local*(MAX_SOCK)+3+m_iPortCount[ port_idx];

      //bind the socket to the local port
      m_wTDIAddress.sin_port = htons( (u_short)0);
      i = bind( m_sSocket[ sock_idx], (SOCKADDR *)&m_wTDIAddress, sizeof( m_wTDIAddress));

      if (!i)
      {

        //the actual connect
        if (!local)
        {

          m_wRemoteAddress.sin_port = htons( (u_short)m_iPort[ port_idx]);

          //connect to remote CTMS
          if (!(i = connect( m_sSocket[ sock_idx], (SOCKADDR *) &m_wRemoteAddress, sizeof( m_wRemoteAddress))))
            m_iConnectionState[ local] = 10;
          else
            //check if connection is pending
            if (WSAGetLastError() == WSAEWOULDBLOCK)
              m_iConnectionState[ local] = 9;
            else
              m_iConnectionState[ local] = 3;
        }
        else
        {

          m_wLocalAddress.sin_port = htons( (u_short)m_iPort[ port_idx]);

          if (!(i = connect( m_sSocket[ sock_idx], (SOCKADDR *) &m_wLocalAddress, sizeof( m_wLocalAddress))))
            m_iConnectionState[ local] = 10;
          else
            //check if connection is pending
            if (WSAGetLastError() == WSAEWOULDBLOCK)
              m_iConnectionState[ local] = 9;
            else
              m_iConnectionState[ local] = 3;
        }
      }
      else m_iConnectionState[ local] = 3; //try again
      break;

    /////////////////////////////////////////////
    // Check connection build 2
    case 9:

      //port index
      port_idx = (local*MAX_PORT) + 1;

      //socket index
      sock_idx = local*(MAX_SOCK)+3+m_iPortCount[ port_idx];

      //fill structures with sockets to observe
      FD_ZERO( &efds);
      FD_SET( m_sSocket[ sock_idx], &efds);
      FD_ZERO( &wfds);
      FD_SET( m_sSocket[ sock_idx], &wfds);

      //connect is pending, wait for completion
      if ((i = select( 0, NULL, &wfds, &efds, &t)) == SOCKET_ERROR)
        m_iConnectionState[ local] = 3; //try again
      else
      {

        //receive the port numbers
        if (i) 
        {
        
          //connection establshed?
          if (FD_ISSET( m_sSocket[ sock_idx], &wfds))
          {

            if (m_iPortCount[ port_idx]) 
              m_iConnectionState[ local] = 10;
            else
            {

              m_iPortCount[ port_idx]++;
              m_iConnectionState[ local] = 8;
            }
          }

          //just disconnect all the sockets and try again    
          if (FD_ISSET( m_sSocket[ sock_idx], &efds))
            m_iConnectionState[ local] = 3;
        }
      }
      break;

    /////////////////////////////////////////////
    // connect port 3
    case 10:

      //port index
      port_idx = (local*MAX_PORT) + 2;

      //socket index
      sock_idx = local*(MAX_SOCK)+5+m_iPortCount[ port_idx];

      //bind the socket to the local port
      if (!(i = bind( m_sSocket[ sock_idx], (SOCKADDR *)&m_wTDIAddress, sizeof( m_wTDIAddress))))
      {

        //the actual connect
        if (!local)
        {

          m_wRemoteAddress.sin_port = htons( (u_short)m_iPort[ port_idx]);

          //connect to remote CTMS
          if (!(i = connect( m_sSocket[ sock_idx], (SOCKADDR *) &m_wRemoteAddress, sizeof( m_wRemoteAddress))))
            m_iConnectionState[ local] = 12;
          else
            //check if connection is pending
            if (WSAGetLastError() == WSAEWOULDBLOCK)
              m_iConnectionState[ local] = 11;
            else
              m_iConnectionState[ local] = 3;
        }
        else
        {

          m_wLocalAddress.sin_port = htons( (u_short)m_iPort[ port_idx]);

          if (!(i = connect( m_sSocket[ sock_idx], (SOCKADDR *) &m_wLocalAddress, sizeof( m_wLocalAddress))))
            m_iConnectionState[ local] = 12;
          else
            //check if connection is pending
            if (WSAGetLastError() == WSAEWOULDBLOCK)
              m_iConnectionState[ local] = 11;
            else
              m_iConnectionState[ local] = 3;
        }
      }
      else m_iConnectionState[ local] = 3; //try again
      break;

    /////////////////////////////////////////////
    // Check connection build 3
    case 11:

      //port index
      port_idx = (local*MAX_PORT) + 2;

      //socket index
      sock_idx = local*(MAX_SOCK)+5+m_iPortCount[ port_idx];

      //fill structures with sockets to observe
      FD_ZERO( &efds);
      FD_SET( m_sSocket[ sock_idx], &efds);
      FD_ZERO( &wfds);
      FD_SET( m_sSocket[ sock_idx], &wfds);

      //connect is pending, wait for completion
      if ((i = select( 0, NULL, &wfds, &efds, &t)) == SOCKET_ERROR)
        m_iConnectionState[ local] = 3; //try again
      else
      {

        //receive the port numbers
        if (i) 
        {
        
          //connection establshed?
          if (FD_ISSET( m_sSocket[ sock_idx], &wfds))
          {

            if (m_iPortCount[ port_idx]) 
              m_iConnectionState[ local] = 12;
            else
            {

              m_iPortCount[ port_idx]++;
              m_iConnectionState[ local] = 10;
            }
          }

          //just disconnect all the sockets and try again    
          if (FD_ISSET( m_sSocket[ sock_idx], &efds))
            m_iConnectionState[ local] = 3;
        }
      }
      break;

    /////////////////////////////////////////////
    // connect port 4
    case 12:

      //port index
      port_idx = (local*MAX_PORT) + 3;

      //socket index
      sock_idx = local*(MAX_SOCK)+7+m_iPortCount[ port_idx];

      //bind the socket to the local port
      if (!(i = bind( m_sSocket[ sock_idx], (SOCKADDR *)&m_wTDIAddress, sizeof( m_wTDIAddress))))
      {

        //the actual connect
        if (!local)
        {

          m_wRemoteAddress.sin_port = htons( (u_short)m_iPort[ port_idx]);

          //connect to remote CTMS
          if (!(i = connect( m_sSocket[ sock_idx], (SOCKADDR *) &m_wRemoteAddress, sizeof( m_wRemoteAddress))))
            m_iConnectionState[ local] = 14;
          else
            //check if connection is pending
            if (WSAGetLastError() == WSAEWOULDBLOCK)
              m_iConnectionState[ local] = 13;
            else
              m_iConnectionState[ local] = 3;
        }
        else
        {

          m_wLocalAddress.sin_port = htons( (u_short)m_iPort[ port_idx]);

          if (!(i = connect( m_sSocket[ sock_idx], (SOCKADDR *) &m_wLocalAddress, sizeof( m_wLocalAddress))))
            m_iConnectionState[ local] = 14;
          else
            //check if connection is pending
            if (WSAGetLastError() == WSAEWOULDBLOCK)
              m_iConnectionState[ local] = 13;
            else
              m_iConnectionState[ local] = 3;
        }
      }
      else m_iConnectionState[ local] = 3; //try again
      break;

    /////////////////////////////////////////////
    // Check connection build 4
    case 13:

      //port index
      port_idx = (local*MAX_PORT) + 3;

      //socket index
      sock_idx = local*(MAX_SOCK)+7+m_iPortCount[ port_idx];

      //fill structures with sockets to observe
      FD_ZERO( &efds);
      FD_SET( m_sSocket[ sock_idx], &efds);
      FD_ZERO( &wfds);
      FD_SET( m_sSocket[ sock_idx], &wfds);

      //connect is pending, wait for completion
      if ((i = select( 0, NULL, &wfds, &efds, &t)) == SOCKET_ERROR)
        m_iConnectionState[ local] = 3; //try again
      else
      {

        //receive the port numbers
        if (i) 
        {
        
          //connection establshed?
          if (FD_ISSET( m_sSocket[ sock_idx], &wfds))
          {

            if (m_iPortCount[ port_idx]) 
              m_iConnectionState[ local] = 14;
            else
            {

              m_iPortCount[ port_idx]++;
              m_iConnectionState[ local] = 12;
            }
          }

          //just disconnect all the sockets and try again    
          if (FD_ISSET( m_sSocket[ sock_idx], &efds))
            m_iConnectionState[ local] = 3;
        }
      }
      break;

    /////////////////////////////////////////////
    // Connection is build
    case 14: m_iConnected[ local] = 1; m_iRestart[ local] = 1; 
      
      //send the last 5 status messages
      if (!local){
       
        //SendData( 2, 3, local, -1);
        SendData( 2, 2, local, -1);
      }

      //send all parameters to CTMS
      for (i = 147; i <= 213; i++)
        m_iHistPara[ i][ 0] = m_iHistPara[ i][ 1] = 1;
      for (i = 214; i <= 288; i++)
        m_iHistPara[ i][ 0] = m_iHistPara[ i][ 1] = 1;
      for (i = 491; i <= 516; i++)
        m_iHistPara[ i][ 0] = m_iHistPara[ i][ 1] = 1;

      //set the global change flag
      m_iParaChanged[ local] = 1; 
      SendData( 2, 11, local, -1);
      break;
    
    default: UnLock( local); return;
  }

  UnLock( local);
}

/////////////////////////////////////////////////////////////////////////////
// Open a socket for use, set all options etc.
// An index is supplied to get all four connections (1 .. 4) and zero
// for the common connection.
/////////////////////////////////////////////////////////////////////////////
void CTMS::CreateSocket(int index)
{

  struct LINGER;
  unsigned long opt; 

  //only if we have a closed socket
  if (m_sSocket[ index] != INVALID_SOCKET) return;

  //open the socket
  m_sSocket[ index] = socket( AF_INET, SOCK_STREAM, IPPROTO_IP);

  //set the options we need
  if (m_sSocket[ index] != INVALID_SOCKET)
  {

    opt = TRUE;
    setsockopt( m_sSocket[ index], SOL_SOCKET, SO_DONTLINGER, (char *)&opt, sizeof( opt));

    //non blocking mode
    opt = -1;
    ioctlsocket( m_sSocket[ index], FIONBIO, &opt);
  }
}


/////////////////////////////////////////////////////////////////////////////
// Disconnect and close socket
/////////////////////////////////////////////////////////////////////////////
void CTMS::DeleteSocket(int index)
{

  //disconnect an dclose socket
  shutdown( m_sSocket[ index], FD_READ|FD_WRITE);
  closesocket( m_sSocket[ index]);
  m_sSocket[ index] = INVALID_SOCKET;

  //remove counter
  if (((index > 0) && (index < MAX_SOCK-1)) ||
      ((index > MAX_SOCK) && (index < 2*MAX_SOCK-1)))
  {

    int i = index - 1;
    int k = 0;
    if (index > MAX_SOCK)
    {

      k = 4;
      i -= MAX_SOCK;
    }
    if ((i+1) >= MAX_SOCK/2) i = i - MAX_SOCK/2 + 1;

    m_iPortCount[ i+k] = 0;
  }
}


/////////////////////////////////////////////////////////////////////////////
// 
// Communication with CTMS, function can be called as often as desired.
// Connection losses are detected, and result in a disconnect. According
// to the protocol changed data is send to the CTMS if there is a connection,
// present: remote and/or local. Every function call a connection (local and 
// remote) is check for data.
// Connection build up is initiated from this function, only if there is a
// connection with a CTMS dat ais exchanged, both the connection to the local 
// and the remote CTMS are handled.
//
/////////////////////////////////////////////////////////////////////////////
void CTMS::Communication()
{

  int i;


  for (i = 0; i < 2; i++)
  {

    //make sure there is a connection
    Connection( (i == CTMS_REMOTE) ? CTMS_REMOTE_PORT: CTMS_LOCAL_PORT, i);

    //data can only be received if there is a connection
    if( IsConnected( i))
    {

      int k, disconnect;

      //check for any data in the system receive buffer
      for (k = 0; k < MAX_PORT; k++)
      {

        if (Receive( m_cBuffer[ k+(MAX_PORT*i)], 2048, &m_iBufferLength[ k+(MAX_PORT*i)], m_sSocket[ (2*k)+(MAX_SOCK*i)+2], &disconnect))
        {

          ReceiveData( &m_cBuffer[ k+(MAX_PORT*i)][ CTMS_HDR], 
                       (int)m_cBuffer[ k+(MAX_PORT*i)][3]*256 + (int)m_cBuffer[ k+(MAX_PORT*i)][2] - CTMS_HDR - CTMS_FTR,
                       i);
          m_iBufferLength[ k+(MAX_PORT*i)] = 0;
        }
        else
        {

          if (disconnect) Disconnect( i);
        }
      }
    }

    //alarm message
    if (Get( m_plVolgnr_Storingsmeldingen) != m_iStorigsmeldingenOld)
      if (SendData( 2, 5, i)) Disconnect( i);

    //status message 
    if (Get( m_plVolgnr_Statusmeldingen) != m_iStatusmeldingenOld)
      if (SendData( 2, 2, i)) Disconnect( i);

    //end of measurement
    if (Get( m_plVolgnr_Meetperiode) != m_iVolgnr_MeetperiodeOld)
    {

      //state message
      if (SendData( 2, 2, i)) Disconnect( i);

      //cluster 11
      if (SendData( 2, 8, i, 11)) Disconnect( i);

      //logging activated
      if (Get( 96))
      {

        //cluster 12
        if (SendData( 2, 8, i, 12)) Disconnect( i);

        //cluster 13
        if (SendData( 2, 8, i, 13)) Disconnect( i);
      }
    }

    //one or more parameters are changed
    if (!m_iParaChanged[ i]) m_sClock[ i] = clock();
    else
    {

      //only send something if we have a connection
////      if (IsConnected( i))
////      {

        if (clock() > (m_sClock[ i] + (CLOCKS_PER_SEC * 2)))
          if (SendData( 2, 11, i)) Disconnect( i);
        else
          if (clock() < m_sClock[ i])
            m_sClock[ i] = clock();
////      }
    }
  }

  //remove changes
  m_iStorigsmeldingenOld = Get( m_plVolgnr_Storingsmeldingen);
  m_iStatusmeldingenOld = Get( m_plVolgnr_Statusmeldingen);
  m_iVolgnr_MeetperiodeOld = Get( m_plVolgnr_Meetperiode);
}


/////////////////////////////////////////////////////////////////////////////
// Lock object
/////////////////////////////////////////////////////////////////////////////
void CTMS::Lock( int local)
{

  //wait for the semaphore
  if (m_hSemaphore[ local])
    WaitForSingleObject( m_hSemaphore[ local], INFINITE);
}

/////////////////////////////////////////////////////////////////////////////
// Unlock object
/////////////////////////////////////////////////////////////////////////////
void CTMS::UnLock( int local)
{

  //release the semaphore
  ReleaseSemaphore( m_hSemaphore[ local], 1, NULL);
}


/////////////////////////////////////////////////////////////////////////////
// Reset a connection
/////////////////////////////////////////////////////////////////////////////
void CTMS::Disconnect(int local)
{

  //there must be a connection before it can be terminated
  if (!m_iConnectionState[ local]) return;

  Lock( local);

  //do a disconnect
  m_iConnectionState[ local] = 3;

  //be a little fast..
  m_iConnected[ local] = 0;

  UnLock( local);
}

/////////////////////////////////////////////////////////////////////////////
// Start a connection build
/////////////////////////////////////////////////////////////////////////////
void CTMS::Connect( int local)
{

  Lock( local);

  //can only connect if there is no connection and no connection building
  if (!m_iConnectionState[ local])
    m_iConnectionState[ local] = 1;

  UnLock( local);
}


/////////////////////////////////////////////////////////////////////////////
// Send a message to the CTMS, message is identified from group and code.
/////////////////////////////////////////////////////////////////////////////
int CTMS::SendData(int Group, int Code, int Local, int Parameter)
{

  int prio;
  unsigned char buf[ 1024];
  unsigned char *data = &buf[3];
  unsigned char *para = &buf[2];
  int cluster;
  int  i;


  //first two bytes of data
  buf[ 0] = (unsigned char)Group;
  buf[ 1] = (unsigned char)Code;

  //evaluate the group and get all relevant data
  switch (Group)
  {

    //group 2
    case 2:

      //evaluate the code
      switch (Code)
      {

        case 1: prio = 4; *para = (unsigned char)Parameter; break; //NAK
        case 2: prio = 1; *para = (unsigned char)0; cluster = 40;
          //check first if old messages are present
          if (IsConnected( Local) && m_iStatusHist[ Local])
          {

            do
            {

              //get the history buffer
              memcpy( data, m_cStatus[ 0+(Local*CTMS_STATUS_MAX)], CTMS_STATUS);
              data += CTMS_STATUS;
              int x = Send( buf, data - buf, m_sSocket[ Local*(MAX_SOCK)+1+(2*prio)]);
              //int x = Send( buf, data - buf, m_sSocket[ Local*(MAX_SOCK)+1+(2*prio)]);

              //reset data ponter to original value
              data = &buf[3];

              //quit if there is an error
              if (x) return x;

              for( i = 0; i < (m_iStatusHist[ Local] - 1); i++)
                memcpy( m_cStatus[ i+(Local*CTMS_STATUS_MAX)], m_cStatus[ i+1+(Local*CTMS_STATUS_MAX)], CTMS_STATUS);

              m_iStatusHist[ Local]--;

            } while (m_iStatusHist[ Local]);
          }

          for (i = 0; i < ClusterGetSize( cluster); data += GetBytes(ClusterGetItem( cluster, i)), i++)
            Get2Uchar( ClusterGetItem( cluster, i), data, FALSE);

          //save the cluster info if there is no connection
          if (!IsConnected( Local))
          {

            //a maximum of 5 messages is saved, skip oldest if needed
            if (m_iStatusHist[ Local] >= CTMS_STATUS_MAX)
            {
              for( i = 0; i < (CTMS_STATUS_MAX - 1); i++)
                memcpy( m_cStatus[ i+(Local*CTMS_STATUS_MAX)], m_cStatus[ i+1+(Local*CTMS_STATUS_MAX)], CTMS_STATUS);

              m_iStatusHist[ Local] = CTMS_STATUS_MAX;
            }
            else
              m_iStatusHist[ Local]++;

            //fill the buffer
            memcpy( m_cStatus[ (m_iStatusHist[ Local]-1)+(Local*CTMS_STATUS_MAX)], &buf[3], CTMS_STATUS);
          }

          //forget the actual one if Parameter is not equal to zero
          if (Parameter) return 0;
          break;
        case 3: prio = 4; *para = (unsigned char)0; cluster = 41;
          for (i = 0; i < ClusterGetSize( cluster); data += GetBytes(ClusterGetItem( cluster, i)), i++)
            Get2Uchar( ClusterGetItem( cluster, i), data, FALSE);
          break;
        case 4: prio = 4; *para = (unsigned char)0; cluster = 42;
          for (i = 0; i < ClusterGetSize( cluster); data += GetBytes(ClusterGetItem( cluster, i)), i++)
            Get2Uchar( ClusterGetItem( cluster, i), data, FALSE);
          break;
        case 5: prio = 3; *para = (unsigned char)Get( 331); cluster = 43;
          for (i = 0; i < ClusterGetSize( cluster); data += GetBytes(ClusterGetItem( cluster, i)), i++)
            Get2Uchar( ClusterGetItem( cluster, i), data, FALSE);
          break;
        case 6: prio = 3; *para = (unsigned char)Get( 332); cluster = 44;
          for (i = 0; i < ClusterGetSize( cluster); data += GetBytes(ClusterGetItem( cluster, i)), i++)
            Get2Uchar( ClusterGetItem( cluster, i), data, FALSE);
          break;
        case 7: prio = 4; *para = (unsigned char)Get( 330); cluster = 45;
          for (i = 0; i < ClusterGetSize( cluster); data += GetBytes(ClusterGetItem( cluster, i)), i++)
            Get2Uchar( ClusterGetItem( cluster, i), data, FALSE);
          break;
        case 8: prio = 4; *para = (unsigned char)Parameter; cluster = Parameter;
          for (i = 0; i < ClusterGetSize( cluster); data += GetBytes(ClusterGetItem( cluster, i)), i++)
            Get2Uchar( ClusterGetItem( cluster, i), data, FALSE);
          break;
        case 9: prio = 4; *para = (unsigned char)Parameter; cluster = Parameter;
          for (i = 0; i < ClusterGetSize( cluster); i++)
          {
            Set( 619, ClusterGetItem( cluster, i)); //save the parameter number
            Get2Uchar( 619, data, FALSE);
            data += GetBytes( 619);
          }
          break;
        case 10: prio = 4; *para = (unsigned char)0;
          for (data[0] = 0, data[ 1] = 0, i = CLUSTER_USER_MIN; i <= CLUSTER_USER_MAX; i++)
            if (!ClusterGetSize( i)) 
            {
              *data += 1; //count number of undefined clusters
              if (!data[1]) data[ 1] = i; //first free cluster
            }

          data += 2;
          *data = (unsigned char)1;
          data++;
          break;
        case 11: prio = 2; *para = (unsigned char)0;
          if (!m_iParaChanged[ Local]) break;
          //send all the parmeters
          for( buf[ 2] = 0, i = 0; i < CTMS_PARAMETER_MAX; i++)
          {

            if (!m_iHistPara[ i][ Local]) continue;

            buf[ 2]++; //count the number changes

            Set( 618, i); //save the parameter number
            Get2Uchar( 618, data, FALSE);
            data += GetBytes( 618);

            Get2Uchar( i, data, FALSE);
            data += GetBytes( i);
            m_iHistPara[ i][ Local] = 0;

            //there is maximum of 40 changes
            if (buf[2] >= 40) 
            {
              //send the data
              int x = Send( buf, data - buf, m_sSocket[ (Local*MAX_SOCK)+(2*prio)-1]);
              if (x) return x; //quit if there is an error
              buf[ 2] = 0;
              data = &buf[ 3];
            }
          }
          //check if all changes are to be send
          if (i >= CTMS_PARAMETER_MAX) m_iParaChanged[ Local] = 0;
          if (*para == 0) return 0; //there must be something to send
          break;
        case 12: prio = 4; *para = (unsigned char)Get( 620); break;
        default: return 0;
      }
      break;

    //group 4
    case 4:

      //evaluate the code
      switch (Code)
      {

        case 2: prio = 4; *para = (unsigned char)0;
          *data = (unsigned char)(m_iRestart[ Local] ? 2: 0);
          data++;
        default: return 0;
      }
      break;

    default: return 0;
  }

  //check if there is a connection with CTMS
  if (!IsConnected( Local)) return 0;

  //do the real sending
  i = ((data - buf) >= 3) ? data - buf: 0;
  return Send( buf, i, m_sSocket[ (Local*MAX_SOCK)+(2*prio)-1]); //success
}

/////////////////////////////////////////////////////////////////////////////
// Send a message to the CTMS, message is identified from group and code.
/////////////////////////////////////////////////////////////////////////////
int CTMS::ReceiveData( unsigned char *Buf, int Length, int Local)
{

  int group = (int)Buf[ 0];
  int code = (int)Buf[ 1];
  int para = (int)Buf[ 2];
  unsigned char *data = &Buf[ 3];
  int cluster;
  int i;
  int len;


  //evaluate the group and get all relevant data
  switch (group)
  {

    //group 0
    case 0:

      //evaluate the code
      switch (code)
      {

        case 1: cluster = 46;
          for (i = 0; i < ClusterGetSize( cluster); data += GetBytes(ClusterGetItem( cluster, i)), i++)
            Uchar2Set( ClusterGetItem( cluster, i), data, FALSE);
          break;
        case 2: cluster = 47;
          for (i = 0; i < ClusterGetSize( cluster); data += GetBytes(ClusterGetItem( cluster, i)), i++)
            Uchar2Set( ClusterGetItem( cluster, i), data, FALSE);
          break;
        case 3: cluster = para;
          //check length of message
          for (i = 0, len = 0; i < ClusterGetSize( cluster); i++)
            len += GetBytes( ClusterGetItem( cluster, i));

          //send nak for incorect length
          if (len != (Length -3)) return SendData( 2, 1, Local, 2);

          //get the new parameter values
          for (i = 0; i < ClusterGetSize( cluster); data += GetBytes(ClusterGetItem( cluster, i)), i++)
            Uchar2Set( ClusterGetItem( cluster, i), data, FALSE);
          break;
        case 4: cluster = para;
          //check cluster number
          if ((cluster < CLUSTER_USER_MIN) || (cluster > CLUSTER_USER_MAX))
            return SendData( 2, 1, Local, 4);

          //first dleete the cluster definition
          ClusterDelete( cluster);

          //now we can add all the new definitions
          for (i = 0; i < ClusterGetSize( cluster); i++)
          {
            Uchar2Set( 619, data, FALSE);
            ClusterAddItem( cluster, (short)Get( 619));
          }
        default: return 0;
      }
      break;

    //group 1
    case 1:

      //evaluate the code
      switch (code)
      {

        case 0: return SendData( 2, 2, Local);
        case 1: return SendData( 2, 3, Local);
        case 2: return SendData( 2, 4, Local);
        case 3: return SendData( 2, 5, Local);
        case 4: return SendData( 2, 6, Local);
        case 5: return SendData( 2, 7, Local);
        case 6: return SendData( 2, 8, Local, para);
        case 7: if ((para < 0) || (para >= MAX_CLUSTERS)) SendData( 2, 2, Local, 4);
          return SendData( 2, 9, Local, para);
        case 8: return SendData( 2, 10, Local);
        case 9:
          //mark all parameters as chaged
          for( i = 0; i < CTMS_PARAMETER_MAX; i++)
            m_iHistPara[ i][ Local] = 1;

          //there is more then one change...
          m_iParaChanged[ Local] = 1;
          return SendData( 2, 11, Local);
        case 10: return SendData( 2, 12, Local);
        default: return 0;
      }
      break;

    //group 3
    case 3:

      //evaluate the code
      switch (code)
      {

        case 3: return SendData( 4, 2, Local);
        default: return 0;
      }
      break;

    //group 5
    case 5:  return 0;

    default: return 0;
  }
  return 0;
}


//////////////////////////////////////////////////////////////////////
// void CTMS::GetHostAddress()
// 
// 
//////////////////////////////////////////////////////////////////////
BOOL CTMS::GetHostAddress()
{

  //retrieve IP-address form INI-file, this is the default address
  m_wTDIAddress.sin_addr.S_un.S_addr = inet_addr ( m_oINIFile.GetString( "IPTDILocal", "CTMS", "0.0.0.0"));

  //IP address defined in ini file, use this one
  //Address 0.0.0.0 will return FALSE, this means were gone find a network card
  if (m_wTDIAddress.sin_addr.S_un.S_addr) return TRUE;

  //find our default IP-address
  char buf[80];
  PHOSTENT ph;

  //get our own IP address
  //if (gethostname ( buf, 80)) buf[0] = '\0';
  if (gethostname ( buf, 80)) return FALSE;

  ph = gethostbyname( buf);

  //set out IP address
  if (ph)
    memcpy( (char *)&(m_wTDIAddress.sin_addr), ph->h_addr_list[0], ph->h_length);

  return TRUE;
}
