/**
*	loop over the DataTemplateInfo (fieldinfo,datainfo) to get the IPFIX values to store in database
*/
char* getRecData(IpfixDbWriter* ipfixDbWriter,Table* table, SourceID* sourceID,
		 DataTemplateInfo* dataTemplateInfo,uint16_t length, FieldData* data)
{
	int i ,j, k, n;
	uint64_t intdata = 0;
	uint32_t flowstartsec = 0;
	/**begin query string for insert statement*/
	char insert[STARTLEN+(table->countCol * INS_WIDTH)];
	strcpy(insert,"INSERT INTO ");
	
	/**make string for the column names*/
	char ColNames[table->countCol * INS_WIDTH];
	strcpy(ColNames," (");
	
	/**make string for the values  given by the IPFIX_TYPEID stored in the record*/ 
	char ColValues[table->countCol * INS_WIDTH]; 
	strcpy(ColValues," VALUES (");	
	
	char stringtmp[INS_WIDTH];// needed to cast from char to string
			
	/**loop over the columname and loop over the IPFIX_TYPEID of the record
	   to get the corresponding */
	/**data to store and make insert statement*/
	for( i=0; i < table->countCol; i++) {
		for( j=0; strcmp(identify[j].cname,"END") != 0; j++) { 
			if(columnsNames[i] == identify[j].cname) {	
				int notfound = 1;
				strncat(ColValues,"'",sizeof(char)+1);
				strncat(ColNames,columnsNames[i],strlen(columnsNames[i])+1);
				if( i != table->countCol-1)
					strncat(ColNames,",",sizeof(char)+1);
				if( i == table->countCol-1)
					strncat(ColNames,") ",(2*sizeof(char))+1);
				if(dataTemplateInfo->fieldCount > 0) {
					for(k=0; k < dataTemplateInfo->fieldCount; k++) {	
						if(dataTemplateInfo->fieldInfo[k].type.id == identify[j].ipfixId) {
							notfound = 0;						
							intdata = getdata(dataTemplateInfo->fieldInfo[k].type,(data+dataTemplateInfo->fieldInfo[k].offset));
							sprintf(stringtmp,"%Lu",(uint64_t)intdata);
							strncat(ColValues,stringtmp,strlen(stringtmp)+1);
							strncat(ColValues,"'",sizeof(char)+1);
							if(identify[j].ipfixId == IPFIX_TYPEID_flowStartSeconds) {
								flowstartsec = intdata;
							}
							if( i !=  table->countCol-1)
								strncat(ColValues,",",sizeof(char)+1);
							if( i == table->countCol-1)
								strncat(ColValues,")",sizeof(char)+1);	
							break;
						}
					}	
				}
				if( dataTemplateInfo->dataCount > 0 && notfound) {
					for(n=0; n < dataTemplateInfo->dataCount; n++) {
						if(dataTemplateInfo->dataInfo[n].type.id == identify[j].ipfixId) {
							notfound = 0;
							intdata = getdata(dataTemplateInfo->dataInfo[n].type,(dataTemplateInfo->data+dataTemplateInfo->dataInfo[n].offset));
							sprintf(stringtmp,"%Lu",(uint64_t)intdata);
							strncat(ColValues,stringtmp,strlen(stringtmp)+1);
							strncat(ColValues,"'",sizeof(char)+1);
							if( i != table->countCol-1)
								strncat(ColValues,",",sizeof(char)+1);
							if( i == table->countCol-1)
								strncat(ColValues,")",sizeof(char)+1);					
							break;
						}
					}
				}
				if(notfound) {	
					if(identify[j].ipfixId == EXPORTERID) {
						/**lookup exporter buffer to get exporterID from sourcID and expIp**/
						uint32_t expID = getExporterID(ipfixDbWriter, table, sourceID);
						sprintf(stringtmp,"%u",(uint32_t)expID);
						strncat(ColValues,stringtmp,strlen(stringtmp)+1);
						strncat(ColValues,"'",sizeof(char)+1);
					} else {
						intdata = getdefaultIPFIXdata(identify[j].ipfixId);
						sprintf(stringtmp,"%Lu",(uint64_t)intdata);
						strncat(ColValues,stringtmp,strlen(stringtmp)+1);
						strncat(ColValues,"'",sizeof(char)+1);
					}
					if( i != table->countCol-1)
						strncat(ColValues,",",sizeof(char)+1);
					if( i == table->countCol-1)
						strncat(ColValues,")",sizeof(char)+1);					
				}
			}
		}
	}
	
	/**make hole query string for the insert statement*/
	char tablename[TABLE_WIDTH] ;
	char* tablen = getTableName(ipfixDbWriter, table, flowstartsec);
	strcpy(tablename, tablen);
	/** Insert statement = INSERT INTO + tablename +  Columnsname + Values of record*/
	strncat(insert, tablename,strlen(tablename)+1);  
	strncat(insert,ColNames,strlen(ColNames)+1);
	strncat(insert,ColValues, strlen(ColValues)+1);
	
	
	char* insertTableStr = (char*) malloc((strlen(insert)+1)*sizeof(char));
	strcpy(insertTableStr,insert);
		
	return insertTableStr;
}
/**
 *	loop over properties and template to get the IPFIX values in correct order to store in database
 *	The result is written to BSON Object, and flowstart is returned
 */
mongo::BSONObj IpfixDbWriterMongo::getInsertObj(const IpfixRecord::SourceID& sourceID,
		TemplateInfo& dataTemplateInfo,uint16_t length, IpfixRecord::Data* data)
{
	uint64_t intdata = 0;
	uint64_t intdata2 = 0;
	uint32_t k;
	bool notfound, notfound2;
	mongo::BSONObjBuilder obj;

	time_t flowstartsec = 0;

	if (!allProp) {
	/** loop over a subset of elements (selected properties) and loop over the IPFIX_TYPEID of the record
	 *  to get the corresponding data to store and make insert statement
	 */
		for(vector<Property>::iterator prop = documentProperties.begin(); prop != documentProperties.end(); prop++) {
			if (prop->ipfixId == EXPORTERID) {
				// if this is the same source ID as last time, we get the exporter id from currentExporter
				if ((currentExporter != NULL) && equalExporter(sourceID, currentExporter->sourceID)) {
					DPRINTF("Exporter is same as last time (ODID=%d, id=%d)", sourceID.observationDomainId, currentExporter->id);
					intdata = (uint64_t)currentExporter->id;
				} else {
				// lookup exporter buffer to get exporterID from sourcID and expIp
					intdata = (uint64_t)getExporterID(sourceID);
				}
			} else {
				notfound = true;
				// try to gather data required for the field
				if(dataTemplateInfo.fieldCount > 0) {
					// look inside the ipfix record
					for(k=0; k < dataTemplateInfo.fieldCount; k++) {
						if( dataTemplateInfo.fieldInfo[k].type.enterprise ==  prop->enterprise &&
							dataTemplateInfo.fieldInfo[k].type.id == prop->ipfixId) {
							notfound = false;
							intdata = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset));
							DPRINTF("IpfixDbWriterMongo::getData: really saw ipfix id %d in packet with intdata %llX, type %d, length %d and offset %X",
							  prop->ipfixId, intdata, dataTemplateInfo.fieldInfo[k].type.id, dataTemplateInfo.fieldInfo[k].type.length,
							  dataTemplateInfo.fieldInfo[k].offset);
							break;
						}
					}
				}
				if( dataTemplateInfo.dataCount > 0 && notfound) {
					// look in static data fields of template for data
					for(k=0; k < dataTemplateInfo.dataCount; k++) {
						if(dataTemplateInfo.fieldInfo[k].type.enterprise == prop->enterprise && dataTemplateInfo.dataInfo[k].type.id == prop->ipfixId) {
							notfound = false;
							intdata = getData(dataTemplateInfo.dataInfo[k].type,(dataTemplateInfo.data+dataTemplateInfo.dataInfo[k].offset));
							break;
						}
					}
				}
				if(notfound) {
					notfound2 = true;
					// for some Ids, we have an alternative
					if(prop->enterprise == 0) {
						switch (prop->ipfixId) {
							case IPFIX_TYPEID_flowStartSeconds:
								if(dataTemplateInfo.fieldCount > 0) {
									for(k=0; k < dataTemplateInfo.fieldCount; k++) {
										// look for alternative (flowStartMilliseconds/1000)
										if(dataTemplateInfo.fieldInfo[k].type.id == IPFIX_TYPEID_flowStartMilliseconds) {
											intdata = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset)) / 1000;
											notfound = false;
											break;
										}
										// if no flow start time is available, maybe this is is from a netflow from Cisco
										// then - as a last alternative - use flowStartSysUpTime as flow start time
										if(dataTemplateInfo.fieldInfo[k].type.id == IPFIX_TYPEID_flowStartSysUpTime) {
											intdata2 = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset));
											notfound2 = false;
										}
									}
									if(notfound && !notfound2) {
										intdata = intdata2;
										notfound = false;
									}
								}
								break;
							case IPFIX_TYPEID_flowEndSeconds:
								if(dataTemplateInfo.fieldCount > 0) {
									for(k=0; k < dataTemplateInfo.fieldCount; k++) {
										// look for alternative (flowEndMilliseconds/1000)
										if(dataTemplateInfo.fieldInfo[k].type.id == IPFIX_TYPEID_flowEndMilliseconds) {
											intdata = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset)) / 1000;
											notfound = false;
											break;
										}
										// if no flow end time is available, maybe this is from a netflow from Cisco
										// then use flowEndSysUpTime as flow start time
										if(dataTemplateInfo.fieldInfo[k].type.id == IPFIX_TYPEID_flowEndSysUpTime) {
											intdata2 = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset));
											notfound2 = false;
										}
									}
									if(notfound && !notfound2) {
										intdata = intdata2;
										notfound = false;
									}
								}
								break;
						}
					} else if (prop->enterprise==IPFIX_PEN_reverse) {
						switch (prop->ipfixId) {
							case IPFIX_TYPEID_flowStartSeconds:
								// look for alternative (revFlowStartMilliseconds/1000)
								if(dataTemplateInfo.fieldCount > 0) {
									for(k=0; k < dataTemplateInfo.fieldCount; k++) {
										if(dataTemplateInfo.fieldInfo[k].type == InformationElement::IeInfo(IPFIX_TYPEID_flowStartMilliseconds, IPFIX_PEN_reverse)) {
											intdata = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset)) / 1000;
											notfound = false;
											break;
										}
									}
								}
								break;
							case IPFIX_TYPEID_flowEndSeconds:
								// look for alternative (revFlowEndMilliseconds/1000)
								if(dataTemplateInfo.fieldCount > 0) {
									for(k=0; k < dataTemplateInfo.fieldCount; k++) {
										if(dataTemplateInfo.fieldInfo[k].type == InformationElement::IeInfo(IPFIX_TYPEID_flowEndMilliseconds, IPFIX_PEN_reverse)) {
											intdata = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset)) / 1000;
											notfound = false;
											break;
										}
									}
								}
								break;

						}
					}
					// if still not found, get default value
					if(notfound)
						intdata = prop->defaultValue;
				}

				// we need extra treatment for timing related fields
				if(prop->enterprise == 0 ) {
					switch (prop->ipfixId) {
						case IPFIX_TYPEID_flowStartSeconds:
							// save time for table access
							if (flowstartsec==0) flowstartsec = intdata;
							break;

						case IPFIX_TYPEID_flowEndSeconds:
							break;

						case IPFIX_TYPEID_flowStartMilliseconds:
							// if flowStartSeconds is not stored in one of the columns, but flowStartMilliseconds is,
							// then we use flowStartMilliseconds for table access
							// This is realized by storing this value only if flowStartSeconds has not yet been seen.
							// A later appearing flowStartSeconds will override this value.
							if (flowstartsec==0)
								flowstartsec = intdata/1000;
						case IPFIX_TYPEID_flowEndMilliseconds:
							// in the database the millisecond entry is counted from last second
							intdata %= 1000;
							break;
					}
				} else if (prop->enterprise==IPFIX_PEN_reverse)
					switch (prop->ipfixId) {
						case IPFIX_TYPEID_flowStartMilliseconds:
						case IPFIX_TYPEID_flowEndMilliseconds:
							// in the database the millisecond entry is counted from last second
							intdata %= 1000;
							break;
					}
			}
		msg(MSG_DEBUG, "saw ipfix id %s (element ID %d) in packet with intdata %llX", prop->propertyName,
							prop->ipfixId, static_cast<int64_t>(intdata));
					if (beautyProp)
						obj << prop->propertyName << static_cast<long long int>(intdata);
					else
						obj << boost::lexical_cast<std::string>(prop->ipfixId).c_str() << static_cast<long long int>(intdata);
						
					if (flowstartsec == 0) {
						msg(MSG_ERROR, "IpfixDbWriterMongo: Failed to get timing data from record. Will be saved in default table.");
					}
			}
		} else {
			/* Dump all elements to DB */
			if(dataTemplateInfo.fieldCount > 0) {
				// look in ipfix records
				for(int k=0; k < dataTemplateInfo.fieldCount; k++) {
						intdata = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset));
						DPRINTF("IpfixDbWriterMongo::getData: dumping from packet intdata %llX, type %d, length %d and offset %X",
						  intdata, dataTemplateInfo.fieldInfo[k].type.id, dataTemplateInfo.fieldInfo[k].type.length,
						  dataTemplateInfo.fieldInfo[k].offset);
						obj << boost::lexical_cast<std::string>(dataTemplateInfo.fieldInfo[k].type.id).c_str() << static_cast<long long int>(intdata);
					}
				}
			
			if( dataTemplateInfo.dataCount > 0) {
				// look in static data fields of template for data
				for(int k=0; k < dataTemplateInfo.dataCount; k++) {
						intdata = getData(dataTemplateInfo.dataInfo[k].type,(dataTemplateInfo.data+dataTemplateInfo.dataInfo[k].offset));
						obj << boost::lexical_cast<std::string>(dataTemplateInfo.fieldInfo[k].type.id).c_str() << static_cast<long long int>(intdata);
					}
				}
		}
	return obj.obj();
}
/**
 *	loop over the IpfixRecord::DataTemplateInfo (fieldinfo,datainfo) to get the IPFIX values to store in database
 *	The result is written into statemStr which must have sufficient space!
 */
char* IpfixDbWriter::getInsertStatement(char* statemStr, IpfixRecord::SourceID* sourceID,
                                        IpfixRecord::DataTemplateInfo* dataTemplateInfo,uint16_t length, IpfixRecord::Data* data, char** locks, int maxlocks)
{
    int j, k;
    uint64_t intdata = 0;
    uint32_t flowstartsec = 0;

    /**begin query string for insert statement*/
    strcpy(statemStr,"INSERT INTO ");

    /**make string for the column names*/
    char ColNames[numberOfColumns * INS_WIDTH];
    strcpy(ColNames," (");

    /**make string for the values  given by the IPFIX_TYPEID stored in the record*/
    char ColValues[numberOfColumns * INS_WIDTH];
    strcpy(ColValues," VALUES (");

    /**loop over the columname and loop over the IPFIX_TYPEID of the record
     to get the corresponding data to store and make insert statement*/
    for( j=0; identify[j].cname != 0; j++) {
        bool notfound = true;

        if (identify[j].ipfixId == EXPORTERID) {
            /**lookup exporter buffer to get exporterID from sourcID and expIp**/
            uint32_t expID = getExporterID(sourceID);
            intdata = expID;
            notfound = false;
        }
        else {
            // try to gather data required for the field
            if(dataTemplateInfo->fieldCount > 0) {
                // look inside the ipfix data packet
                for(k=0; k < dataTemplateInfo->fieldCount; k++) {
                    if(dataTemplateInfo->fieldInfo[k].type.id == identify[j].ipfixId) {
                        notfound = false;
                        intdata = getdata(dataTemplateInfo->fieldInfo[k].type,(data+dataTemplateInfo->fieldInfo[k].offset));
                        DPRINTF("IpfixDbWriter::getRecData: really saw ipfix id %d in packet with intdata %llX, type %d, length %d and offset %X", identify[j].ipfixId, intdata, dataTemplateInfo->fieldInfo[k].type.id, dataTemplateInfo->fieldInfo[k].type.length, dataTemplateInfo->fieldInfo[k].offset);
                    }
                }
            }
            if( dataTemplateInfo->dataCount > 0 && notfound) {
                // look in static data fields of template for data
                for(k=0; k < dataTemplateInfo->dataCount; k++) {
                    if(dataTemplateInfo->dataInfo[k].type.id == identify[j].ipfixId) {
                        notfound = false;
                        intdata = getdata(dataTemplateInfo->dataInfo[k].type,(dataTemplateInfo->data+dataTemplateInfo->dataInfo[k].offset));
                    }
                }
            }
            if(notfound) {
                // for some Ids, we have an alternative
                switch (identify[j].ipfixId) {
                case IPFIX_TYPEID_flowStartSeconds:
                    // look for alternative (flowStartMilliSeconds/1000)
                    if(dataTemplateInfo->fieldCount > 0) {
                        for(k=0; k < dataTemplateInfo->fieldCount; k++) {
                            if(dataTemplateInfo->fieldInfo[k].type.id == IPFIX_TYPEID_flowStartMilliSeconds) {
                                intdata = getdata(dataTemplateInfo->fieldInfo[k].type,(data+dataTemplateInfo->fieldInfo[k].offset)) / 1000;
                                notfound = false;
                                break;
                            }
                        }
                    }
                    break;
                case IPFIX_ETYPEID_revFlowStartSeconds:
                    // look for alternative (revFlowStartMilliSeconds/1000)
                    if(dataTemplateInfo->fieldCount > 0) {
                        for(k=0; k < dataTemplateInfo->fieldCount; k++) {
                            if(dataTemplateInfo->fieldInfo[k].type.id == IPFIX_ETYPEID_revFlowStartMilliSeconds) {
                                intdata = getdata(dataTemplateInfo->fieldInfo[k].type,(data+dataTemplateInfo->fieldInfo[k].offset)) / 1000;
                                notfound = false;
                                break;
                            }
                        }
                    }
                    break;
                case IPFIX_TYPEID_flowEndSeconds:
                    // look for alternative (flowEndMilliSeconds/1000)
                    if(dataTemplateInfo->fieldCount > 0) {
                        for(k=0; k < dataTemplateInfo->fieldCount; k++) {
                            if(dataTemplateInfo->fieldInfo[k].type.id == IPFIX_TYPEID_flowEndMilliSeconds) {
                                intdata = getdata(dataTemplateInfo->fieldInfo[k].type,(data+dataTemplateInfo->fieldInfo[k].offset)) / 1000;
                                notfound = false;
                                break;
                            }
                        }
                    }
                    break;
                case IPFIX_ETYPEID_revFlowEndSeconds:
                    // look for alternative (revFlowEndMilliSeconds/1000)
                    if(dataTemplateInfo->fieldCount > 0) {
                        for(k=0; k < dataTemplateInfo->fieldCount; k++) {
                            if(dataTemplateInfo->fieldInfo[k].type.id == IPFIX_ETYPEID_revFlowEndMilliSeconds) {
                                intdata = getdata(dataTemplateInfo->fieldInfo[k].type,(data+dataTemplateInfo->fieldInfo[k].offset)) / 1000;
                                notfound = false;
                                break;
                            }
                        }
                    }
                    break;
                }
                // if still not found, get default value
                if(notfound)
                    intdata = getdefaultIPFIXdata(identify[j].ipfixId);
            }

            // we need extra treatment for timing related fields
            switch (identify[j].ipfixId) {
            case IPFIX_TYPEID_flowStartSeconds:
                // save time for table access
                printf("intdata (seconds): %llu\n", intdata);
                if (flowstartsec==0) flowstartsec = intdata;
                break;

            case IPFIX_TYPEID_flowStartMilliSeconds:
                // if flowStartSeconds is not stored in one of the columns, but flowStartMilliSeconds is,
                // the we use flowStartMilliSeconds for table access
                // This is realized by storing this value only if flowStartSeconds has not yet been seen.
                // A later appearing flowStartSeconds will override this value.
                printf("intdata (milliseconds): %llu\n", intdata);
                if (flowstartsec==0)
                    flowstartsec = intdata/1000;
                // in the database the millisecond entry is counted from last second
                intdata %= 1000;
                break;


            case IPFIX_TYPEID_flowEndMilliSeconds:
            case IPFIX_ETYPEID_revFlowStartMilliSeconds:
            case IPFIX_ETYPEID_revFlowEndMilliSeconds:
                // in the database the millisecond entry is counted from last second
                intdata %= 1000;
                break;
            }
        }

        DPRINTF("saw ipfix id %d in packet with intdata %llX", identify[j].ipfixId, intdata);

        addColumnEntry(ColNames, identify[j].cname, false, j==numberOfColumns-1);
        addColumnEntry(ColValues, intdata, true, j==numberOfColumns-1);
    }

    printf("colnames: '%s', colvals: '%s'\n", ColNames, ColValues);
    if (flowstartsec == 0) {
        printf("failed to get timing data\n");
        //THROWEXCEPTION("failed to get timing data from ipfix packet. this is a critical error at the moment, as no valid table can be determined. Aborting");
        return "";
    }

    /**make whole query string for the insert statement*/
    char tablename[TABLE_WIDTH];
    DPRINTF("flowstartsec: %d", flowstartsec);
    const char* tablen = getTableName(flowstartsec);
    strcpy(tablename, tablen);
    /** Insert statement = INSERT INTO + tablename +  Columnsname + Values of record*/
    strcat(statemStr, tablename);
    strcat(statemStr, ColNames);
    strcat(statemStr, ColValues);

    /* insert table name into locks if necessary */
    for(j=0; j < maxlocks; j++) {
        if(locks[j][0] == '\0') {
            /* empty slot, i.e. no more table names. insert the current one */
            strcpy(locks[j], tablename);
            break;
        }
        else if(strncmp(tablename, locks[j], TABLE_WIDTH) == 0)
            /* found tablename */
            break;
    }

    return statemStr;
}
/**
 *	loop over table columns and template to get the IPFIX values in correct order to store in database
 *	The result is written into row, the firstSwitched time is returned in flowstartsec
 */
string& IpfixDbWriter::getInsertString(string& row, time_t& flowstartsec, const IpfixRecord::SourceID& sourceID,
		TemplateInfo& dataTemplateInfo,uint16_t length, IpfixRecord::Data* data)
{
	uint64_t intdata = 0;
	uint64_t intdata2 = 0;
	uint32_t k;
	bool notfound, notfound2;
	bool first = true;
	ostringstream rowStream(row);

	flowstartsec = 0;
	rowStream << "(";

	/**loop over the columname and loop over the IPFIX_TYPEID of the record
	 to get the corresponding data to store and make insert statement*/
	for(vector<Column>::iterator col = tableColumns.begin(); col != tableColumns.end(); col++) {
		if (col->ipfixId == EXPORTERID) {
			// if this is the same source ID as last time, we get the exporter id from currentExporter
			if ((currentExporter != NULL) && equalExporter(sourceID, currentExporter->sourceID)) {
				DPRINTF("Exporter is same as last time (ODID=%d, id=%d)", sourceID.observationDomainId, currentExporter->id);
				intdata = (uint64_t)currentExporter->id;
			} else {
			// lookup exporter buffer to get exporterID from sourcID and expIp
				intdata = (uint64_t)getExporterID(sourceID);
			}
		} else {
			notfound = true;
			// try to gather data required for the field
			if(dataTemplateInfo.fieldCount > 0) {
				// look inside the ipfix record
				for(k=0; k < dataTemplateInfo.fieldCount; k++) {
					if(dataTemplateInfo.fieldInfo[k].type.enterprise ==  col->enterprise && dataTemplateInfo.fieldInfo[k].type.id == col->ipfixId) {
						notfound = false;
						intdata = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset));
						DPRINTF("IpfixDbWriter::getData: really saw ipfix id %d in packet with intdata %llX, type %d, length %d and offset %X", col->ipfixId, intdata, dataTemplateInfo.fieldInfo[k].type.id, dataTemplateInfo.fieldInfo[k].type.length, dataTemplateInfo.fieldInfo[k].offset);
						break;
					}
				}
			}
			if( dataTemplateInfo.dataCount > 0 && notfound) {
				// look in static data fields of template for data
				for(k=0; k < dataTemplateInfo.dataCount; k++) {
					if(dataTemplateInfo.fieldInfo[k].type.enterprise == col->enterprise && dataTemplateInfo.dataInfo[k].type.id == col->ipfixId) {
						notfound = false;
						intdata = getData(dataTemplateInfo.dataInfo[k].type,(dataTemplateInfo.data+dataTemplateInfo.dataInfo[k].offset));
						break;
					}
				}
			}
			if(notfound) {
				notfound2 = true;
				// for some Ids, we have an alternative
				if(col->enterprise == 0) {
					switch (col->ipfixId) {
						case IPFIX_TYPEID_flowStartSeconds:
							if(dataTemplateInfo.fieldCount > 0) {
								for(k=0; k < dataTemplateInfo.fieldCount; k++) {
									// look for alternative (flowStartMilliSeconds/1000)
									if(dataTemplateInfo.fieldInfo[k].type.id == IPFIX_TYPEID_flowStartMilliSeconds) {
										intdata = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset)) / 1000;
										notfound = false;
										break;
									}
									// if no flow start time is available, maybe this is is from a netflow from Cisco
									// then - as a last alternative - use flowStartSysUpTime as flow start time
									if(dataTemplateInfo.fieldInfo[k].type.id == IPFIX_TYPEID_flowStartSysUpTime) {
										intdata2 = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset));
										notfound2 = false;
									}
								}
								if(notfound && !notfound2) {
									intdata = intdata2;
									notfound = false;
								}
							}
							break;
						//TODO: replace by enterprise number (Gerhard 12/2009)
						case IPFIX_ETYPEID_revFlowStartSeconds:
							// look for alternative (revFlowStartMilliSeconds/1000)
							if(dataTemplateInfo.fieldCount > 0) {
								for(k=0; k < dataTemplateInfo.fieldCount; k++) {
									if(dataTemplateInfo.fieldInfo[k].type.id == IPFIX_ETYPEID_revFlowStartMilliSeconds) {
										intdata = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset)) / 1000;
										notfound = false;
										break;
									}
								}
							}
							break;
						case IPFIX_TYPEID_flowEndSeconds:
							if(dataTemplateInfo.fieldCount > 0) {
								for(k=0; k < dataTemplateInfo.fieldCount; k++) {
									// look for alternative (flowEndMilliSeconds/1000)
									if(dataTemplateInfo.fieldInfo[k].type.id == IPFIX_TYPEID_flowEndMilliSeconds) {
										intdata = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset)) / 1000;
										notfound = false;
										break;
									}
									// if no flow end time is available, maybe this is is from a netflow from Cisco
									// then use flowEndSysUpTime as flow start time
									if(dataTemplateInfo.fieldInfo[k].type.id == IPFIX_TYPEID_flowEndSysUpTime) {
										intdata2 = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset));
										notfound2 = false;
									}
								}
								if(notfound && !notfound2) {
									intdata = intdata2;
									notfound = false;
								}
							}
							break;
						//TODO: replace by enterprise number (Gerhard 12/2009)
						case IPFIX_ETYPEID_revFlowEndSeconds:
							// look for alternative (revFlowEndMilliSeconds/1000)
							if(dataTemplateInfo.fieldCount > 0) {
								for(k=0; k < dataTemplateInfo.fieldCount; k++) {
									if(dataTemplateInfo.fieldInfo[k].type.id == IPFIX_ETYPEID_revFlowEndMilliSeconds) {
										intdata = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset)) / 1000;
										notfound = false;
										break;
									}
								}
							}
							break;
					}
				}
				// if still not found, get default value
				if(notfound)
					intdata = col->defaultValue;
			}

			// we need extra treatment for timing related fields
			if(col->enterprise == 0 ) {
				switch (col->ipfixId) {
					case IPFIX_TYPEID_flowStartSeconds:
						// save time for table access
						if (flowstartsec==0) flowstartsec = intdata;
						break;
						
					case IPFIX_TYPEID_flowEndSeconds:
						break;

					case IPFIX_TYPEID_flowStartMilliSeconds:
						// if flowStartSeconds is not stored in one of the columns, but flowStartMilliSeconds is,
						// then we use flowStartMilliSeconds for table access
						// This is realized by storing this value only if flowStartSeconds has not yet been seen.
						// A later appearing flowStartSeconds will override this value.
						if (flowstartsec==0)
							flowstartsec = intdata/1000;
					case IPFIX_TYPEID_flowEndMilliSeconds:
					//TODO: replace by enterprise number (Gerhard 12/2009)
					case IPFIX_ETYPEID_revFlowStartMilliSeconds:				
					case IPFIX_ETYPEID_revFlowEndMilliSeconds:
						// in the database the millisecond entry is counted from last second
						intdata %= 1000;
						break;
				}
			}
		}
		
		DPRINTF("saw ipfix id %d in packet with intdata %llX", col->ipfixId, intdata);

		if(first)
			rowStream << intdata;
		else
			rowStream << "," << intdata;
		first = false;
	}
	
	rowStream << ")";

	if (flowstartsec == 0) {
		msg(MSG_ERROR, "IpfixDbWriter: Failed to get timing data from record. Will be saved in default table.");
	}

	row = rowStream.str();
	DPRINTF("Insert row: %s", row.c_str());
	return row;
}