<?php

/*
 * Add Ports to Object by reading snmp ifTable / ifxTable / ipAdEntIfIndex 
 * If Port name or L2Address already exists the port is not added.
 *
 * Also bind ip addresses to Object if not already allocated.
 *
 * Won't add anything until "Create Ports and IPs" pressed!
 * 
 *
 * Tested only with some Enterasys switches C/B and S !!!!
 * 
 * 
 * 
 * TESTED on FreeBSD 8.2, nginx/1.0.8, php 5.3.8, NET-SNMP 5.7
 *
 * (c)2011 Maik Ehinger <m.ehinger@ltur.de>
 */

/* TODOs
 * 
 *  - code cleanup
 *  - test and finalize SNMP v3 support
 * 
 *  - set more Object attributs / fields (e.g. HW Type,...)
 *  
 */

/*************************
 * Change Log
 * 
 * 09.12.11	minor cleanups
 *
 */

$tab['object']['snmpgeneric'] = 'SNMP Generic sync';
$tabhandler['object']['snmpgeneric'] = 'snmpgeneric_tabhandler';

/* ifType to RT oif_id mapping */
$ifType2oif_id = array(
	/* 440 causes SQLSTATE[23000]: Integrity constraint violation:
	 *				 1452 Cannot add or update a child row: 
	 *					a foreign key constraint fails
	 */
	//  '1' => 440,		/* other => unknown */
	  '1' => 1469,		/* other => virutal port */
	  '6' => 24,		/* ethernetCsmacd => 1000BASE-T */
	 '24' => 1469,		/* softwareLoopback => virtual port */
	 '33' => 681,		/* rs232 => RS-232 (DB-9) */
	 '34' => 1469, 		/* para => virtual port */
	 '53' => 1469,		/* propVirtual => virtual port */
	 '62' => 1195,		/* fastEther => 100BASE-FX */
	'131' => 1469,		/* tunnel => virtual port */
	'136' => 1469,		/* l3ipvlan => virtual port */
	'160' => 1469,		/* usb => virtual port */
	'161' => 1469,		/* ieee8023adLag => virtual port */
);

/* ignore port are not created */
$ignoreportoif_id = array(
	1469, 	/* virtual port */
	681,	/* RS-232 (DB-9) */
);

$portiifoptions= getPortIIFOptions();
$portiifoptions[-1] = 'sfp'; /* generic sfp */

$portoifoptions= getPortOIOptions();

const SNMP_VERSION = SNMPgeneric::VERSION_2C;
const SNMP_COMMUNITY = 'public';

/* -------------------------------------------------- */

function snmpgeneric_tabhandler($object_id) {

	if(isset($_POST['snmpconfig'])) {
		if($_POST['snmpconfig'] == '1') {
			snmpgeneric_list($object_id);
		}	
	} else {
		snmpconfig();
	}
}

/* -------------------------------------------------- */

function snmpconfig() {

	echo '<h1 align=center>SNMP Config</h1>';
	echo '<p align=center> SNMPv3 untestet !!!</p>';
	echo '<form method=post name=snmpconfig action='.$_SERVER['REQUEST_URI'].' />';
        echo '<table cellspacing=0 cellpadding=5 align=center class=widetable>
        <tr>
                <th class=tdright><label for=snmpversion>Version:</label></th>
                <td class=tdleft><select name=version value=v1 >
			<option value='.SNMPgeneric::VERSION_1.'>v1</options>
			<option value='.SNMPgeneric::VERSION_2C.' selected>v2c</options>
			<option value='.SNMPgeneric::VERSION_3.'>v3</options>
		</td>
        </tr>
        <tr>
                <th class=tdright><label for=community>Community / Security Name:</label></th>
                <td class=tdleft><input type=text name=community value='.SNMP_COMMUNITY.' ></td>
        </tr>
        <tr>
		<th></th>
                <td class=tdleft><p><label>Fields below are for SNMPv3 only</label></p></td>
        </tr>
        <tr>
                <th class=tdright><label">Security Level:</label></th>
                <td class=tdleft><select name="sec_level">
                        <option value="noAuthNoPriv" selected="selected">noAuth and no Priv</option>
                        <option value="authNoPriv" >auth without Priv</option>
                        <option value="authPriv" >auth with Priv</option>
                </select></td>
        </tr>
        <tr>
                <th class=tdright><label>Auth Type:</label></th>
                <td class=tdleft>
                <input name=auth_protocol type=radio value=MD5 /><label>MD5</label>
                <input name=auth_protocol type=radio value=SHA /><label>SHA</label>
                </td>
        </tr>
        <tr>
                <th class=tdright><label>Auth Key:</label></th>
                <td class=tdleft><input type=text id=auth_passphrase name=auth_passphrase></td>
        </tr>
        <tr>
                <th class=tdright><label>Priv Type:</label></th>
                <td class=tdleft>
                <input name=priv_protocol type=radio value=DES /><label>DES</label>
                <input name=priv_protocol type=radio value=AES /><label>AES</label>
                </td>
        </tr>
        <tr>
                <th class=tdright><label>Priv Key</label></th>
                <td class=tdleft><input type=text name=priv_passphrase></td>
        </tr>
        <tr><td colspan=2>

        <input type=hidden name=snmpconfig value=1>
	<input type=submit value="Show List"></td></tr>

        </table></form>';

	
}

function snmpgeneric_list($object_id) {

    	global $username;
	global $ignoreportoif_id;

	$snmpconfig['version'] = SNMP_VERSION;
	$snmpconfig['community'] = SNMP_COMMUNITY;

	$dryrun = true;


	if(isset($_POST['snmpconfig'])) {
		$snmpconfig = $_POST;	
	}

	if(isset($_POST['dryrun'])) {
		$dryrun = $_POST['dryrun'];
	}

	$object = spotEntity ('object', $object_id);
	$object['attr'] = getAttrValues($object_id);

        $endpoints = findAllEndpoints ($object_id, $object['name']);

	$snmpdev = new mySNMP($snmpconfig['version'], $endpoints[0], $snmpconfig['community']);

	if($snmpconfig['version'] == SNMPgeneric::VERSION_3 ) {
		$snmpdev->setSecurity( $snmpconfig['sec_level'],
					$snmpconfig['auth_protocol'],
					$snmpconfig['auth_passphrase'],
					$snmpconfig['priv_protocol'],
					$snmpconfig['priv_passphrase']
					);
	}

	if($snmpdev->getErrno()) {

		showError($snmpdev->getError());

		/* try ip addresses if FQDN does not work */
		foreach( getObjectIPv4Allocations($object_id) as $ip => $value) {
			
			/* skip ips in endpoint array */
			if(in_array($ip, $endpoints))
				continue;

			$snmpdev = new mySNMP($snmpconfig['version'], $ip, $snmpconfig['community']);

			if($snmpconfig['version'] == SNMPgeneric::VERSION_3 ) {
				$snmpdev->setSecurity( $snmpconfig['sec_level'],
							$snmpconfig['auth_protocol'],
							$snmpconfig['auth_passphrase'],
							$snmpconfig['priv_protocol'],
							$snmpconfig['priv_passphrase']
							);
			}

			if($snmpdev->getErrno()) {
				showError($snmpdev->getError());
			} else {
				showNotice("SNMP connect to $ip successfull");
				break;
			}
		};
	}

	if($snmpdev->getErrno()) {
		return;
	}

	if(!$dryrun) {

		/* commitUpdateAttrValue ($object_id, $attr_id, $new_value); */

		/* TODO */
		//commitUpdateAttrValue ($object_id, '2', $dict_key); /* HW type */

		if(empty($object['attr'][14]['value']))
			if(strlen($snmpdev->sysContact))
				commitUpdateAttrValue ($object_id, '14', $snmpdev->sysContact); /* contact person */
	} else
		showNotice("Dry run !!");

	echo "<table>";
	foreach ($snmpdev as $key => $value) {
		echo "<tr><td>$key</td><td>$value</td></tr>";
	}
	echo "</table>";

	$ifsnmp = new ifSNMP($snmpdev);

	echo "<br><br>ifNumber: ".$ifsnmp->ifNumber."<br>";

	$objectports = getPortsNameL2address($object_id);

	$portcompat = getPortInterfaceCompat();

	$ifsnmp->printifInfoTableHeader("<th>add port</th><th>add ip</th><th>porttypeid</th><th>comment</th></tr>");

	foreach($ifsnmp as $if) {

		$createport = TRUE;

		$comment = "";

		if(trim($ifsnmp->ifName($if)) == '') {
			$comment .= "no ifName";
			$createport = FALSE;
		} else {

			if(array_key_exists($ifsnmp->ifName($if),$objectports)){
				$comment .= "Name exists";
				$createport = FALSE;
			}
		}

		if($ifsnmp->ifPhysAddress($if) != '' ) {
			if(in_array($ifsnmp->ifPhysAddress($if),$objectports)){
				$comment .= ", L2Address exists";
				$createport = FALSE;
			}
		}


		$porttypeid = guessRToif_id($ifsnmp->ifType($if), $ifsnmp->ifDescr($if));
		
		/* ignore ports  (virtual ports) */
		if (in_array($porttypeid,$ignoreportoif_id)) {
			$comment .= " ignore Port";
			$createport = FALSE;
		}

		/* ignore ports without on Connector */
		if($ifsnmp->ifConnectorPresent($if) == 2) {
			$comment .= ", no Connector";
			$createport = FALSE;
		}


		
		if($createport) {

			if(!$dryrun)
 				commitAddPort ($object_id, $ifsnmp->ifName($if), $porttypeid, $ifsnmp->ifDescr($if), $ifsnmp->ifPhysAddress($if));

			$portcreate = "yes";
		} else
			$portcreate = "no";


		/* Allocate IPs */
		$createipaddr = FALSE;		
		$ipaddrcreate = "no";

		$ipaddr = $ifsnmp->ipaddress($if);

		if( $ipaddr != '' ) {

			if($ipaddr != '127.0.0.1') {

				/* TODO getIPAdressNetworkId */

				$address = getIPAddress($ipaddr);

				/* only if ip not already allocated */
				if(empty($address['allocs'])) {
					$createipaddress = TRUE;
					$ipaddrcreate = "yes";

					if(!$dryrun)
						bindIpToObject($ipaddr, $object_id,$ifsnmp->ifName($if),1); /* connected */
				}
			}
		}
		
		$ifsnmp->printifInfoTableRow($if,"<td>$portcreate</td><td>$ipaddrcreate</td><td>$porttypeid</td><td>$comment</td>");

	}

	echo "</table>";

	if($dryrun) {
		echo '<p><form align=right name=CreatePorts method=post action='.$_SERVER['REQUEST_URI'].'><input type=hidden name=dryrun value=0 />';

		/* preserve snmpconfig */
		foreach($_POST as $key => $value) {
			echo '<input type=hidden name='.$key.' value='.$value.' />';
		}

		echo '<input type=submit value="Create Ports and IPs"></form></p>';
//		echo '<p align="right"><a href="'.$_SERVER['REQUEST_URI'].htmlspecialchars('&dryrun=0').'">!! Create Ports and IPs !!</a></p>';
	} else
		echo "<p>next page??</p>"; 

}

/* -------------------------------------------------- */

/* returns RT interface type depending on ifType, ifDescr, .. */
function guessRToif_id($ifType,$ifDescr = NULL) {
	global $ifType2oif_id;
	global $portiifoptions;
	global $portoifoptions;

	/* default value */
	$retval = '24'; /* 1000BASE-T */

	if(isset($ifType2oif_id[$ifType])) {
		$retval = $ifType2oif_id[$ifType];
	}

	if($ifType != 6) 
		return $retval;


	/* try to identify outer and inner interface type from ifDescr */

	/**********************
	 * ifDescr samples
	 *
	 * Enterasys C3
	 *
	 * Unit: 1 1000BASE-T RJ45 Gigabit Ethernet Frontpanel Port 45 - no sfp inserted
	 * Unit: 1 1000BASE-T RJ45 Gigabit Ethernet Frontpanel Port 47 - sfp 1000BASE-SX inserted
	 *
	 *
	 * Enterasys S4
	 *
         * Enterasys Networks, Inc. 1000BASE Gigabit Ethernet Port; No GBIC/MGBIC Inserted
	 * Enterasys Networks, Inc. 1000BASE-SX Mini GBIC w/LC connector
	 * Enterasys Networks, Inc. 10GBASE SFP+ 10-Gigabit Ethernet Port; No SFP+ Inserted
	 * Enterasys Networks, Inc. 10GBASE-SR SFP+ 10-Gigabit Ethernet Port (850nm Short Wavelength, 33/82m MMF, LC)
	 * Enterasys Networks, Inc. 1000BASE Gigabit Ethernet Port; Unknown GBIC/MGBIC Inserted
 	 *
	 */

	foreach($portiifoptions as $iif_id => $iif_type) {
		
		/* TODO better matching */


		/* find iif_type */
		if(preg_match('/(.*?)('.preg_quote($iif_type).')(.*)/i',$ifDescr,$matches)) {

			$oif_type = "empty ".$iif_type;

			$no = preg_match('/ no $/i', $matches[1]);

			if(preg_match('/(\d+[G]?)BASE[^ ]+/i', $matches[1], $basematch)) {
				$oif_type=$basematch[0];
			} else {
				if(preg_match('/(\d+[G]?)BASE[^ ]+/i', $matches[3], $basematch)) {
					$oif_type=$basematch[0];
				}
			}

			if($iif_id == -1) {
				/* 2 => SFP-100 or 4 => SFP-1000 */

				if(isset($basematch[1])) {
					switch($basematch[1]) {
						case '100' :
							$iif_id = 2;
							$iif_type = "SFP-100";
							break;
						default:
						case '1000' :
							$iif_id = 4;	
							$iif_type = "SFP-1000";
							break;
					}
				}
				
			}

			if($no) {
				$oif_type = "empty ".$iif_type;
			}

			$oif_type = preg_replace('/BASE/',"Base",$oif_type);

			$oif_id = array_search($oif_type,$portoifoptions);

			if($oif_id != '') {
				$retval = "$iif_id-$oif_id";
			}

			/* TODO check port compat */

			/* stop foreach */
			break;
		}
	}

	return $retval;

}

/* --------------------------------------------------- */

/* returns Ports Name and L2Address as associated array Name => L2Address */
function getPortsNameL2address($my_object_id)
{
        $result = usePreparedSelectBlade
        (
                'SELECT name,l2address FROM Port WHERE object_id = ? ORDER BY name',
                array ($my_object_id)
        );
        $row = $result->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_UNIQUE|PDO::FETCH_COLUMN);

        return $row;
}

/* returns Ports Name and L2Address as associated array Name => L2Address */
function getPortOIOptions()
{
        $result = usePreparedSelectBlade
        (
		'SELECT dict_key,dict_value from Dictionary where chapter_id = 2',
                array ()
        );
        $row = $result->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_UNIQUE|PDO::FETCH_COLUMN);
        return $row;
}



/* ------------------------------------------------------- */
class SNMPgeneric {

	protected $host;
	protected $version;

	/* SNMPv1 and SNMPv2c */
	protected $community;

	/* SNMPv3 */
	protected $sec_level;
	protected $auth_protocol;
	protected $auth_passphrase;
	protected $priv_protocol;
	protected $priv_passphrase;
//	protected $contextName;
//	protected $contextEngineID;

	const VERSION_1 = 1;
	const VERSION_2C = 2;
	const VERSION_3 = 3;


	protected $result;

	function __construct($version, $host, $community) {
		
		$this->host = $host;
		$this->version = $version;
		$this->community = $community;	

		//snmp_set_valueretrieval(SNMP_VALUE_LIBRARY);

		/* Return values without SNMP type hint */
		snmp_set_valueretrieval(SNMP_VALUE_PLAIN);

	//	snmp_set_oid_output_format(SNMP_OID_OUTPUT_FULL);
		
	//	snmp_set_quick_print(1);

	}

	function __destruct() {
	}

	function setSecurity($sec_level, $auth_protocol = 'md5', $auth_passphrase = '', $priv_protocol = 'des', $priv_passphrase = '') {
		$this->sec_level = $sec_level;
		$this->auth_protocol = $auth_protocol;
		$this->auth_passphrase = $auth_passphrase;
		$this->priv_protocol = $priv_protocol;
		$this->priv_passphrase = $priv_passphrase;
	}

	function walk( $oid, $suffix_as_key = FALSE) {

		switch($this->version) {
			case self::VERSION_1:
				if($suffix_as_key){
					$this->result = snmpwalk($this->host,$this->community,$oid);
				} else {
					$this->result = snmprealwalk($this->host,$this->community,$oid);
				}
				break;

			case self::VERSION_2C:
				if($suffix_as_key){
					$this->result = snmp2_walk($this->host,$this->community,$oid);
				} else {
					$this->result = snmp2_real_walk($this->host,$this->community,$oid);
				}
				break;

			case self::VERSION_3:
				if($suffix_as_key){
					$this->result = snmp3_walk($this->host,$this->community, $this->sec_level, $this->auth_protocol, $this->auth_passphrase, $this->priv_protocol, $this->priv_passphrase,$oid);
				} else {
					$this->result = snmp3_real_walk($this->host,$this->community, $this->sec_level, $this->auth_protocol, $this->auth_passphrase, $this->priv_protocol, $this->priv_passphrase,$oid);
				}
				break;
		}
		return $this->result;
	}

	private function __snmpget($object_id) {

		$retval = FALSE;
		
		switch($this->version) {
			case self::VERSION_1:
				$retval = snmpget($this->host,$this->community,$object_id);
				break;

			case self::VERSION_2C:
				$retval = snmp2_get($this->host,$this->community,$object_id);
				break;

			case self::VERSION_3:
				$retval = snmp3_get($this->host,$this->community, $this->sec-level, $this->auth_protocol, $this->auth_passphrase, $this->priv_protocol, $this->priv_passphrase,$object_id);
				break;
		}

		return $retval;
	}

	function get($object_id, $preserve_keys = false) {

		if(is_array($object_id)) {

			if( $preserve_keys ) {
				foreach($object_id as $oid) {
					$this->result[$oid] = $this->__snmpget($oid);
				}
			} else {
				foreach($object_id as $oid) {
					$result_oid = preg_replace('/.\d$/','',$oid);
					$this->result[$result_oid] = $this->__snmpget($oid);
				}
			}
		} else {
			$this->result = $this->__snmpget($object_id);
		}

		return $this->result;
		
	}

	function close() {
	}

	function getErrno() {
		return ($this->result === FALSE);
	}

	function getError() {
		$var = error_get_last();
		return $var['message'];
	}
}

/* ------------------------------------------------------- */
/*
 * SNMP with system OIDs 
 */
class mySNMP extends SNMPgeneric implements Iterator {

	//private $sysInfo;
	private $system;

	/* is system table available ? */
	private $systemerror = TRUE;

	function __construct($version, $host, $community) {
		parent::__construct($version, $host, $community);

		/* .iso.org.dod.internet.mgmt.mib-2.system */
		$this->system = $this->walk(".1.3.6.1.2.1.1");

		$this->systemerror = $this->getErrno();
		
	}

	function get_new($object_id, $preserve_keys = false) {
		$result = parent::get($object_id,$preserve_keys);
		return $this->removeDatatype($result);
	}

	function walk_new($object_id) {
		$result = parent::walk($object_id);
		return $this->removeDatatype($result);
	}

	/* use snmp_set_valueretrieval(SNMP_VALUE_PLAIN) instead */
	function removeDatatype($val) {
		return preg_replace('/^\w+: /','',$val);
	}

	/* make something like $class->sysDescr work */
	function __get($name) {
		if($this->systemerror) {
			return;
		}
		
		if( isset($this->system["SNMPv2-MIB::$name.0"]))
			return $this->system["SNMPv2-MIB::$name.0"];
		else {
			if( isset($this->system[".iso.org.dod.internet.mgmt.mib-2.system.$name.0"])) {
				return $this->system[".iso.org.dod.internet.mgmt.mib-2.system.$name.0"];
			}
		}

		$trace = debug_backtrace();
        	trigger_error(
            		'Undefinierte Eigenschaft für __call(): ' . $name .
            		' in ' . $trace[0]['file'] .
            		' Zeile ' . $trace[0]['line'],
            		E_USER_NOTICE);
        		return null;
	}


	/* Iteration through all system OIDs */
	/* Iterator */

	function current() {
		if($this->systemerror)
			return;

		return current($this->system);
	}

	function key() {
		if($this->systemerror)
			return;

		return key($this->system);
	}

	function next() {
		return next($this->system);
	}

	function valid() {
		return ($this->current() !== FALSE) & ($this->systemerror !== TRUE);
	}

	function rewind() {
		if($this->systemerror)
			return;

		reset($this->system);
	}

	/* END Iterator */

} /* mySNMP */

/* ------------------------------------------------------- */

class ifSNMP implements Iterator {
	private $snmpdevice;
	private $ifNumber = 0;
	private $ifTable;

	private $interfaceserror = TRUE;

	function __construct(&$snmpdevice) {
		$this->snmpdevice = $snmpdevice;	

		$this->interfaceserror = $this->snmpdevice->getErrno();

		if($this->interfaceserror) {
			return;
		}
		
		$this->ifNumber = intval($this->snmpdevice->get('ifNumber.0'));
		
		$this->interfaceserror = $this->snmpdevice->getErrno();

		if(!$this->interfaceserror) {
			
			$this->getifTable();
		}
		
	}

	function getifTable() {
		$this->ifTable['ifIndex'] = $this->snmpdevice->walk('ifIndex',TRUE);
		$this->ifTable['ifDescr'] = $this->snmpdevice->walk('ifDescr',TRUE);
		$this->ifTable['ifAlias'] = $this->snmpdevice->walk('ifAlias',TRUE);
		$this->ifTable['ifName'] =  $this->snmpdevice->walk('ifName',TRUE);
		
		$this->ifTable['ifType'] =  $this->snmpdevice->walk('ifType',TRUE);

		$this->ifTable['ifSpeed'] =  $this->snmpdevice->walk('ifSpeed',TRUE);

		/* notation changes when SNMP_VALUE_PLAIN is set string -> hex!! */
		$this->ifTable['ifPhysAddress'] =  $this->snmpdevice->walk('ifPhysAddress',TRUE);

		$this->ifTable['ifOperStatus'] =  $this->snmpdevice->walk('ifOperStatus',TRUE);
		$this->ifTable['ifConnectorPresent'] =  $this->snmpdevice->walk('ifConnectorPresent',TRUE);

		/* ip address */
		$ipAdEntIfIndex =  $this->snmpdevice->walk('ipAdEntIfIndex');

		foreach($ipAdEntIfIndex as $oid => $value) {
			$ipaddr = preg_replace('/.*\.([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$/','$1',$oid);
			$this->ifTable['ipaddress'][ array_search($value,$this->ifTable['ifIndex']) ] = $ipaddr;
		}
	}

	function printifInfoTableHeader($suffix = "") {
		if($this->interfaceserror) {
			return;
		}

		echo "<table>";
		echo "<tr>";
		foreach ($this->ifTable as $key => $value) {
			echo "<th>".$key."</th>";
		}
		echo "$suffix</tr>";
	}


	function printifInfoTableRow($ifIndex, $suffix = "") {
		if($this->interfaceserror) {
			return;
		}

		echo "<tr>";
		foreach ($this->ifTable as $key => $value) {
			echo "<td>".$this->{$key}($ifIndex)."</td>";
		}
		echo "$suffix</tr>";
	}

	function formatMACAddr($addr) {

		$retval = '';

		/* TODO test origin format */
		if(strlen($addr)== 6 ) {
			$retval =  unpack('H12',$addr);
			$retval = $retval[1];
		}

		/* often used as loopback on Enterasys switches */
		if($retval == '000000000000') {
			$retval = '';
		}

		return $retval;
	}

	function ifPhysAddress($index) {

		if(isset($this->ifTable['ifPhysAddress'][$index-1])) {
			return strtoupper($this->formatMACAddr($this->ifTable['ifPhysAddress'][$index-1]));
		}
	}

	function ipaddress($index) {
		if(isset($this->ifTable['ipaddress'][$index-1])) {
			return $this->ifTable['ipaddress'][$index-1];
		}

	}

	function __get($name) {

		switch($name) {
			case 'ifNumber': 
				return $this->{$name};
				break;
		}
	
		$trace = debug_backtrace();
        	trigger_error(
            		'Undefinierte Eigenschaft für __get(): ' . $name .
            		' in ' . $trace[0]['file'] .
            		' Zeile ' . $trace[0]['line'],
            		E_USER_NOTICE);
        		return null;
	}

	/* $obj->ifDescr(3) = $ifTable[$name][$arg]*/
	function __call($name,$args) {
		
		if($this->interfaceserror)
			return;
	
		if(isset($this->ifTable[$name])) {
			if(isset($this->ifTable[$name][$args[0]-1])) {
				return $this->ifTable[$name][$args[0]-1];
			}
		}
	

		$trace = debug_backtrace();
        	trigger_error(
            		'Undefinierte Methode für __call(): ' . $name .
            		' in ' . $trace[0]['file'] .
            		' Zeile ' . $trace[0]['line'],
            		E_USER_NOTICE);
        		return null;
	}

	/* Iterator */

	private $IteratorIndex = 1;

	function current() {
		return $this->IteratorIndex;
	}

	function key() {
	}

	function next() {
		$this->IteratorIndex++;
	}

	function valid() {
		return ($this->IteratorIndex<=$this->ifNumber);
	}

	function rewind() {
		$this->IteratorIndex = 1;
	}

	/* END Iterator */
}

/* ------------------------------------------------------- */
/* ------------------------------------------------------- */
/* for debugging */
function sg_var_dump_html(&$var) {
	
	echo "<pre>------------------Start Var Dump -------------------------\n";
	var_dump($var);
	echo "\n---------------------END Var Dump ------------------------</pre>";
}
?>
