<?php

/** We rely on the Horde_Data_imc:: abstract class. */
require_once dirname(__FILE__) . '/imc.php';

/**
 * Implement the Horde_Data:: API for vCard data.
 *
 * $Horde: horde/lib/Data/vcard.php,v 1.18 2003/06/17 23:27:48 slusarz Exp $
 *
 * Copyright 1999-2003 Jan Schneider <jan@horde.org>
 *
 * See the enclosed file COPYING for license information (LGPL). If you
 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
 *
 * @author Jan Schneider <jan@horde.org>
 * @package horde.data
 * @since Horde 3.0
 */
class Horde_Data_vcard extends Horde_Data_imc {

    function importData($text)
    {
        $res = parent::importData($text);
        if (is_a($res, 'PEAR_Error')) {
            return $res;
        }
        return $this->_objects;
    }

    function _build($data, &$i)
    {
        $objects = array();

        while (isset($data[$i])) {
            if (String::upper($data[$i]['name']) != 'BEGIN') {
                return PEAR::raiseError(sprintf(_("Import Error: Expected \"BEGIN\" on line %d."), $i));
            }
            $type = String::upper($data[$i]['values'][0]);
            $object = array('type' => $type);
            $object['objects'] = array();
            $object['params'] = array();
            $i++;
            while (isset($data[$i]) && String::upper($data[$i]['name']) != 'END') {
                if (String::upper($data[$i]['name']) == 'BEGIN') {
                    $object['objects'][] = $this->_build($data, $i);
                } else {
                    $object['params'][] = $data[$i];
                }
                $i++;
            }
            if (!isset($data[$i])) {
                return PEAR::raiseError(_("Import Error: Unexpected end of file."));
            }
            if (String::upper($data[$i]['values'][0]) != $type) {
                return PEAR::raiseError(sprintf(_("Import Error: Type mismatch. Expected \"END:%s\" on line %d."), $type, $i));
            }
            $objects[] = $object;
            $i++;
        }

        $this->_objects = $objects;
    }

    function getValues($attribute, $card = 0)
    {
        $values = array();
        $attribute = String::upper($attribute);

        if (array_key_exists($card, $this->_objects)) {
            for ($i = 0; $i < count($this->_objects[$card]['params']); $i++) {
                $param = $this->_objects[$card]['params'][$i];
                if ($param['name'] == $attribute) {
                    for ($j = 0; $j < count($param['values']); $j++) {
                        $values[] = array('value' => $this->read($param, $j), 'params' => $param['params']);
                    }
                }
            }
        }

        return $values;
    }

    function getBareEmail($address)
    {
        require_once 'Mail/RFC822.php';
        require_once HORDE_BASE . '/lib/MIME.php';

        static $rfc822;
        if (is_null($rfc822)) {
            $rfc822 = new Mail_RFC822();
        }

        $rfc822->validateMailbox($address);

        return MIME::rfc822WriteAddress($address->mailbox, $address->host);
    }

    /**
     * Return a data hash from a vCard object.
     *
     * @param array             $card   The card to convert.
     *
     * @return array $hash   The Turba-format data.
     *
     * @since Horde 3.0
     */
    function toHash($card)
    {
        $hash = array();
        foreach ($card['params'] as $item) {
            switch ($item['name']) {

            case 'FN':
                $hash['name'] = $this->read($item);
                break;

            case 'NICKNAME':
                $hash['alias'] = $this->read($item);
                break;

            // We use LABEL but also support ADR.
            case 'LABEL':
                if (isset($item['params']['HOME'])) {
                    $hash['homeAddress'] = $this->read($item);
                } elseif (isset($item['params']['WORK'])) {
                    $hash['workAddress'] = $this->read($item);
                } else {
                    $hash['workAddress'] = $this->read($item);
                }
                break;

            // for vCard 3.0
            case 'ADR':
                if (isset($item['params']['TYPE'])) {
                    foreach ($item['params']['TYPE'] as $adr) {
                        if (String::upper($adr) == 'HOME') {
                            // Right now, only getting the street
                            // address from the semicolon list.
                            $street = explode(';', $this->read($item));
                            $hash['homeAddress'] = $street[2];
                        } elseif (String::upper($adr) == 'WORK') {
                            $street = explode(';', $this->read($item));
                            $hash['workAddress'] = $street[2];
                        }
                    }
                }
                break;

            // for vCard 3.0
            case 'TEL':
                foreach ($item['params']['TYPE'] as $tel) {
                    if (String::upper($tel) == 'WORK') {
                        $hash['workPhone'] = $this->read($item);
                    } elseif (String::upper($tel) == 'HOME') {
                        $hash['homePhone'] = $this->read($item);
                    } elseif (String::upper($tel) == 'CELL') {
                        $hash['cellPhone'] = $this->read($item);
                    } elseif (String::upper($tel) == 'FAX') {
                        $hash['fax'] = $this->read($item);
                    }
                }
                break;

            case 'EMAIL':
                if (isset($item['params']['PREF']) || !isset($hash['email'])) {
                    $hash['email'] = $this->getBareEmail($this->read($item));
                }
                break;

            case 'TITLE':
                $hash['title'] = $this->read($item);
                break;

            case 'ORG':
                $units = array();
                for ($i = 0; $i < count($item['values']); $i++) {
                    $units[] = $this->read($item, $i);
                }
                $hash['company'] = implode(', ', $units);
                break;

            case 'NOTE':
                $hash['notes'] = $this->read($item);
                break;
            }
        }

        return $hash;
    }

    /**
     * Takes all necessary actions for the given import step, parameters and
     * form values and returns the next necessary step.
     *
     * @access public
     *
     * @param integer $action        The current step. One of the IMPORT_*
     *                               constants.
     * @param optional array $param  An associative array containing needed
     *                               parameters for the current step.
     *
     * @return mixed        Either the next step as an integer constant or imported
     *                      data set after the final step.
     */
    function nextStep($action, $param = array())
    {
        switch ($action) {
        case IMPORT_FILE:
            $res = parent::nextStep($action, $param);
            if (is_a($res, 'PEAR_Error')) {
                return $res;
            }

            $import_data = $this->importFile($_FILES['import_file']['tmp_name']);
            if (is_a($import_data, 'PEAR_Error')) {
                return $import_data;
            }

            /* Build the result data set as an associative array. */
            $data = array();
            foreach ($import_data as $object) {
                if ($object['type'] == 'VCARD') {
                    $data[] = $this->toHash($object);
                }
            }
            return $data;
            break;

        default:
            return parent::nextStep($action, $param);
            break;
        }
    }

}
