<?php

class vCardConverter
{

    const MAX_ATR_LENGTH_40 = 40;
    const MAX_ATR_LENGTH_64 = 64;
    const MAX_ATR_LENGTH_128 = 128;
    const MAX_ATR_LENGTH_255 = 255;

    public $parser;
    public $vCardData;
    public $decodedData;

    public function convertVCardToAddresses($vCard)
    {
        Log::d('Converting vCard to address.', 'iCloudSync [vCardConverter]');
        $parser = new vCardParser();
        $parser->readVCards($vCard);
        $vCardData = $parser->returnData();

        $this->Data = $vCardData;
        $this->setAttributes();

        if ($this->checkForContact()) {
            $this->setData();
            return true;
        }
        return false;
    }

    private function checkForContact()
    {
        if ($this->Data['N']['FirstName'] === null) {
            return false;
        }
        return true;
    }

    private function setAttributes()
    {
        $this->attributes = array(
            'n_family' => '',
            'n_given' => '',
            'n_middle' => '',
            'n_prefix' => '',
            'n_suffix' => '',
            'n_fn' => '',
            'org_name' => '',
            'org_unit' => '',
            'contact_email' => '',
            'contact_email_home' => '',
            'adr_one_street' => '',
            'adr_one_locality' => '',
            'adr_one_region' => '',
            'adr_one_postalcode' => '',
            'adr_one_countryname' => '',
            'adr_two_street' => '',
            'adr_two_locality' => '',
            'adr_two_region' => '',
            'adr_two_postalcode' => '',
            'adr_two_countryname' => '',
            'tel_cell_private' => '',
            'tel_cell' => '',
            'tel_work' => '',
            'tel_home' => '',
            'tel_fax_home' => '',
            'tel_fax' => '',
            'twitter_profile_url' => '',
            'linkedin_profile_url' => '',
            'facebook_profile_url' => '',
            'contact_note' => '',
            'contact_url_home' => '',
            'contact_url' => '',
            'contact_bday' => '',
            'contact_role' => '',
            'source' => AddressSourceType::ICLOUD
        );
    }

    private function setData()
    {
        foreach ($this->Data as $key => $value) {
            switch ($key) {
                case 'N':
                    $this->setNamesFromVCard($key);
                    break;
                case 'FN':
                    $this->attributes['n_fn'] = $this->checkAttributesLength($value, vCardConverter::MAX_ATR_LENGTH_128);
                    break;
                case 'ORG':
                    $this->setOrgFromVCard($key);
                    break;
                case 'ADR':
                    $this->setAddressFromVCard($value);
                    break;
                case 'TITLE':
                    $this->attributes['contact_role'] = $this->checkAttributesLength($value, vCardConverter::MAX_ATR_LENGTH_64);
                    break;
                case 'EMAIL':
                    $this->setEmailFromVCard($value);
                    break;
                case 'item':
                    $this->setItemsFromVCard($value);
                    break;
                case 'TEL':
                    $this->setTelFromVCard($value);
                    break;
                case 'X-SOCIALPROFILE':
                    $this->setSocialMediaFromVCard($value);
                    break;
                case 'NOTE':
                    $this->setNoteFromVCard($value);
                    break;
                case 'URL':
                    $this->setUrlFromVCard($value);
                    break;
                case 'BDAY':
                    $this->attributes['contact_bday'] = $value;
                    break;
                case 'UID':
                    $this->attributes['contact_uid'] = $this->checkAttributesLength($value, vCardConverter::MAX_ATR_LENGTH_255);
                    break;
                case 'PHOTO':
                    $this->setPhotoUrlFromVCard($value);
                    break;
            }
        }
    }

    private function setNamesFromVCard($key)
    {
        $name = $this->Data[$key];
        $this->attributes['n_family'] = $this->checkAttributesLength($name['LastName'], vCardConverter::MAX_ATR_LENGTH_64);
        $this->attributes['n_given'] = $this->checkAttributesLength($name['FirstName'], vCardConverter::MAX_ATR_LENGTH_64);
        $this->attributes['n_middle'] = $this->checkAttributesLength($name['AdditionalNames'], vCardConverter::MAX_ATR_LENGTH_64);
        $this->attributes['n_prefix'] = $this->checkAttributesLength($name['Prefixes'], vCardConverter::MAX_ATR_LENGTH_64);
        $this->attributes['n_suffix'] = $this->checkAttributesLength($name['Suffixes'], vCardConverter::MAX_ATR_LENGTH_64);
    }

    private function setOrgFromVCard($key)
    {
        $org = $this->Data[$key];
        $this->attributes['org_name'] = $this->checkAttributesLength($org['Name'], vCardConverter::MAX_ATR_LENGTH_128);
        $this->attributes['org_unit'] = $this->checkAttributesLength($org['Unit1'], vCardConverter::MAX_ATR_LENGTH_64);
    }

    private function setAddressFromVCard($value)
    {
        foreach ($value as $entry) {
            $this->getAddressType($entry);
        }
    }

    private function setEmailFromVCard($value)
    {
        if ($this->checkForType($value)) {
            $this->attributes['contact_email'] = $this->checkEmailLength($this->getDataFromType('WORK', $value), vCardConverter::MAX_ATR_LENGTH_128);
            $this->attributes['contact_email_home'] = $this->checkEmailLength($this->getDataFromType('HOME', $value), vCardConverter::MAX_ATR_LENGTH_128);
        }
    }

    private function setItemsFromVCard($item)
    {
        foreach ($item as $value) {
            if (array_key_exists('ADR', $value)) {
                $this->getItemAddressFromVCard($value);
            } else if (array_key_exists('TEL', $value)) {
                $this->setTelFromVCard($value);
            } else if (array_key_exists('EMAIL', $value)) {
                $this->setEmailFromVCard($value);
            } else if (array_key_exists('URL', $value)) {
                $this->setUrlFromVCard($value);
            }
        }
    }

    private function getItemAddressFromVCard($value)
    {
        $address = $value['ADR'];
        if (isset($value['type'])) {
            $address['type'] = $value['type'];
            $this->getAddressType($address);
        }
    }

    private function getAddressType($value)
    {
        if (array_key_exists('type', $value)) {
            if (in_array('HOME', $value['type'])) {
                $this->setAddress($value, 'adr_two');
            } elseif (in_array('WORK', $value['type'])) {
                $this->setAddress($value, 'adr_one');
            }
        }
    }

    private function setAddress($value, $adr_type)
    {
        if (empty($this->attributes[$adr_type . '_street']) &&
                empty($this->attributes[$adr_type . '_locality']) &&
                empty($this->attributes[$adr_type . '_region']) &&
                empty($this->attributes[$adr_type . '_postalcode']) &&
                empty($this->attributes[$adr_type . '_countryname'])) {
            $this->attributes[$adr_type . '_street'] = $this->checkAttributesLength($this->getStreetFromVCard($value['StreetAddress']), vCardConverter::MAX_ATR_LENGTH_64);
            $this->attributes[$adr_type . '_locality'] = $this->checkAttributesLength($value['Locality'], vCardConverter::MAX_ATR_LENGTH_64);
            $this->attributes[$adr_type . '_region'] = $this->checkAttributesLength($value['Region'], vCardConverter::MAX_ATR_LENGTH_64);
            $this->attributes[$adr_type . '_postalcode'] = $this->checkAttributesLength($value['PostalCode'], vCardConverter::MAX_ATR_LENGTH_64);
            $this->attributes[$adr_type . '_countryname'] = $this->checkAttributesLength($value['Country'], vCardConverter::MAX_ATR_LENGTH_64);
        }
    }

    private function getStreetFromVCard($street)
    {
        if (strpos($street, '\\n') !== false || strpos($street, '\\n') === 0) {
            $streets = explode('\\n', $street);
            return $streets[0];
        }
        return $street;
    }

    private function setTelFromVCard($value)
    {
        if (!$this->checkForType($value)) {
            return;
        }
        foreach ($value as $entry) {
            if (in_array('VOICE', $entry['type'])) {
                $voice = $this->getVoiceNumbersFromVCard();
                $this->getNumbersFromVCard($voice, $entry);
            } elseif (in_array('FAX', $entry['type'])) {
                $fax = $this->getFaxFromVCard();
                $this->getNumbersFromVCard($fax, $entry);
            }
        }
    }

    private function getVoiceNumbersFromVCard()
    {
        return $voiceNumbers = array(
            'tel_cell_private' => 'IPHONE',
            'tel_cell' => 'CELL',
            'tel_work' => 'WORK',
            'tel_home' => 'HOME',
        );
    }

    private function getFaxFromVCard()
    {
        return $faxNumbers = array(
            'tel_fax_home' => 'HOME',
            'tel_fax' => 'WORK',
        );
    }

    private function getNumbersFromVCard($array, $entry)
    {
        foreach ($array as $key => $value) {
            if (in_array($value, $entry['type']) && empty($this->attributes[$key])) {
                $this->attributes[$key] = $this->checkAttributesLength($entry['value'], vCardConverter::MAX_ATR_LENGTH_40);
                return;
            }
        }
    }

    private function setSocialMediaFromVCard($value)
    {
        if ($this->checkForType($value)) {
            $this->attributes['twitter_profile_url'] = $this->checkAttributesLength($this->getDataFromType('twitter', $value), vCardConverter::MAX_ATR_LENGTH_255);
            $this->attributes['linkedin_profile_url'] = $this->checkAttributesLength($this->getDataFromType('linkedin', $value), vCardConverter::MAX_ATR_LENGTH_255);
            $this->attributes['facebook_profile_url'] = $this->checkAttributesLength($this->getDataFromType('facebook', $value), vCardConverter::MAX_ATR_LENGTH_255);
        }
    }

    private function setNoteFromVCard($value)
    {
        if ((strpos($value, '\\n') !== false) || (strpos($value, '\\n') === 0)) {
            $note = explode('\\n', $value);
            $value = $note[0];
        }
        $this->attributes['contact_note'] = $value;
    }

    private function setUrlFromVCard($value)
    {
        if ($this->checkForType($value)) {
            $this->attributes['contact_url_home'] = $this->checkAttributesLength($this->getDataFromType('HOME', $value), vCardConverter::MAX_ATR_LENGTH_128);
            $this->attributes['contact_url'] = $this->checkAttributesLength($this->getDataFromType('WORK', $value), vCardConverter::MAX_ATR_LENGTH_128);
        }
    }

    private function setPhotoUrlFromVCard($value)
    {
        if (is_array($value)) {
            $this->photo_url = $value['value'];
        } else {
            $this->photo_url = $value;
        }
    }

    public function downloadPhoto($addresses, $photo, $id)
    {
        if (!empty($photo)) {
            $tempPath = Yii::app()->runtimePath . '/' . $id . basename($this->photo_url);
            $file = fopen($tempPath, 'wb');
            fwrite($file, $photo['content']);
            fclose($file);

            if ($addresses->isImage($tempPath)) {
                return $this->setPhotoFromVCard($tempPath, $addresses, $id);
            } else {
                unlink($tempPath);
            }
        }
        return $addresses;
    }

    private function setPhotoFromVCard($tempSrcPath, $addresses, $id)
    {
        $addresses->contact_jpegphoto = '1';
        $addresses->save(false);
        $resize = new ImageResize($tempSrcPath);

        foreach ($addresses->avatarSizes as $size) {
            $tempPath = Yii::app()->runtimePath . "/" . $id . '_' . $size . ".jpg";

            $resize->resizeImage((int) $size, (int) $size, 'crop');
            $resize->saveImage($tempPath, 80);

            $addresses->saveFileToFieldByPath("image_" . $size, $tempPath);
            unlink($tempPath);
        }
        unlink($tempSrcPath);
        return $addresses;
    }

    private function checkForType($value)
    {
        foreach ($value as $data) {
            if (empty($data['type'])) {
                return false;
            }
            return true;
        }
    }

    private function getDataFromType($assignmentData, $vCardData)
    {
        foreach ($vCardData as $entry) {
            if (!isset($entry['type'])) {
                continue;
            }
            if (in_array($assignmentData, $entry['type'])) {
                return $entry['value'];
            }
        }
    }

    public function checkAttributesLength($value, $length)
    {
        if (mb_strlen($value, 'UTF-8') <= $length) {
            return $value;
        }
        return mb_substr($value, 0, $length, 'UTF-8');
    }

    public function checkEmailLength($value, $length)
    {
        if (strlen($value) <= $length) {
            return $value;
        }
        return null;
    }

    public function convertAddressesToVCard($addresses, $vCardData = null)
    {
        Log::d('Converting address to vCard.', 'iCloudSync [vCardExporter]');
        $parser = new vCardParser;
        $this->addresses = $addresses;
        $decodedData = array();

        if (isset($vCardData)) {
            $decodedData = json_decode($vCardData->data, 'true');
        }

        $this->vCard = $decodedData;

        $this->initializeVCardArray();
        $this->prepareDeletionOfEmptyData();

        if (!$this->validateVCard()) {
            unset($this->vCard);
            return;
        }
        $parser->setVCardData($this->vCard);

        $this->setAddressUID($addresses);

        return $parser->writeVCard();
    }

    private function initializeVCardArray()
    {
        $this->vCard['VERSION'] = '3.0';
        $this->vCard['PRODID'] = '-//Apple Inc.//Mac OS X 10.11.4//EN';
        $this->vCard['N'] = $this->setNames();
        $this->vCard['FN'] = $this->setFN();
        $this->vCard['ORG'] = $this->setOrg();
        $this->vCard['TITLE'] = $this->setTitle();
        $this->setEmail();
        $this->setADR();
        $this->setTel();
        $this->setSocialProfile();
        $this->vCard['NOTE'] = trim(preg_replace('/\s+/', ' ', $this->addresses->contact_note));
        $this->setURL();
        $this->vCard['BDAY'] = $this->addresses->contact_bday;
        $this->setPhoto();
        $this->vCard['UID'] = $this->setUID();
    }

    private function setNames()
    {
        return array(
            'LastName' => $this->addresses->n_family,
            'FirstName' => $this->addresses->n_given,
            'AdditionalNames' => $this->addresses->n_middle,
            'Prefixes' => $this->addresses->n_prefix,
            'Suffixes' => $this->addresses->n_suffix
        );
    }

    private function setFN()
    {
        $fn = '';
        $attribute = array('n_prefix', 'n_given', 'n_middle', 'n_family', 'n_suffix');
        foreach ($attribute as $key) {
            if (!empty($this->addresses->$key)) {
                $fn .= $this->addresses->$key . ' ';
            }
        }
        return $fn;
    }

    private function setOrg()
    {
        return array(
            'Name' => $this->addresses->org_name,
            'Unit1' => $this->addresses->org_unit,
            'Unit2' => null,
        );
    }

    private function setTitle()
    {
        if (isset($this->addresses->contact_role)) {
            return $this->addresses->contact_role;
        } elseif (isset($this->vCard['TITLE'])) {
            unset($this->vCard['TITLE']);
        }
    }

    private function setEmail()
    {
        if (!array_key_exists('EMAIL', $this->vCard)) {
            $this->addNewDataToVCardArray('EMAIL', array('contact_email' => array('WORK')));
            $this->addNewDataToVCardArray('EMAIL', array('contact_email_home' => array('HOME')));
        } else {
            $this->ovewriteData('EMAIL', array('contact_email' => 'WORK'));
            $this->ovewriteData('EMAIL', array('contact_email_home' => 'HOME'));
        }
    }

    private function setADR()
    {
        if (!array_key_exists('ADR', $this->vCard)) {
            if (array_key_exists('item', $this->vCard)) {
                $this->checkItem();
            } else {
                $this->checkAlreadySetADR(0, 0);
            }
        } else {
            $this->prepareOverwriteADR();
        }
    }

    private function checkItem()
    {
        $alreadySetHome = 0;
        $alreadySetWork = 0;

        foreach ($this->vCard['item'] as $key => $item) {
            if (!array_key_exists('ADR', $item) || !array_key_exists('type', $item)) {
                continue;
            }
            if (in_array('HOME', $item['type']) && $alreadySetHome != 1) {
                $this->overwriteItemADR('adr_two', $key);
                $alreadySetHome = 1;
            } elseif (in_array('WORK', $item['type']) && $alreadySetWork != 1) {
                $this->overwriteItemADR('adr_one', $key);
                $alreadySetWork = 1;
            }
            if ($alreadySetHome == 1 && $alreadySetWork == 1) {
                return;
            }
        }
        $this->checkAlreadySetADR($alreadySetHome, $alreadySetWork);
    }

    private function overwriteItemADR($adr_type, $key)
    {
        $this->vCard['item'][$key]['ADR'] = array(
            'PoBox' => '',
            'ExtendedAddress' => '',
            'StreetAddress' => $this->setStreets($adr_type, $key),
            'Locality' => $this->addresses[$adr_type . '_locality'],
            'Region' => '',
            'PostalCode' => $this->addresses[$adr_type . '_postalcode'],
            'Country' => $this->addresses[$adr_type . '_countryname'],
        );
    }

    private function setStreets($adr_type, $key)
    {
        if (strpos($this->vCard['item'][$key]['ADR']['StreetAddress'], '\\n')) {
            $streets = explode('\\n', $this->vCard['item'][$key]['ADR']['StreetAddress']);
            $streets[0] = $this->addresses[$adr_type . '_street'];
            return implode('\\n', $streets);
        }
        return $this->addresses[$adr_type . '_street'];
    }

    private function checkAlreadySetADR($alreadySetHome, $alreadySetWork)
    {
        if ($alreadySetHome != 1) {
            $this->checkIfADRDataIsEmpty('adr_two');
        }
        if ($alreadySetWork != 1) {
            $this->checkIfADRDataIsEmpty('adr_one');
        }
    }

    private function checkIfADRDataIsEmpty($adr_type)
    {
        if (!empty($this->addresses[$adr_type . '_street']) || !empty($this->addresses[$adr_type . '_locality']) || !empty($this->addresses[$adr_type . '_postalcode']) || !empty($this->addresses[$adr_type . '_countryname'])) {
            $this->prepareNewADR($adr_type);
        }
    }

    private function prepareNewADR($adr_type)
    {
        if ($adr_type == 'adr_one') {
            $type = 'WORK';
        } else {
            $type = 'HOME';
        }

        if (isset($this->vCard['item'])) {
            $this->vCard['item'][] = $this->setNewADR($adr_type, $type);
        } else {
            $this->vCard['item'][1] = $this->setNewADR($adr_type, $type);
        }
    }

    private function setNewADR($adr_type, $type)
    {
        return array(
            'ADR' => array(
                'PoBox' => '',
                'ExtendedAddress' => '',
                'StreetAddress' => $this->addresses[$adr_type . '_street'],
                'Locality' => $this->addresses[$adr_type . '_locality'],
                'Region' => '',
                'PostalCode' => $this->addresses[$adr_type . '_postalcode'],
                'Country' => $this->addresses[$adr_type . '_countryname'],
            ),
            'type' => array(
                $type
            ),
            'data' => array(
                'X-ABADR' => 'de'
            )
        );
    }

    private function prepareOverwriteADR()
    {
        if (is_array($this->vCard['ADR'])) {
            $this->addADRtoItems();
        } else {
            if (in_array('HOME', $this->vCard['ADR']['type'])) {
                $this->prepareNewADR('adr_two');
            }
            if (in_array('WORK', $this->vCard['ADR']['type'])) {
                $this->prepareNewADR('adr_one');
            }
        }
        if (isset($this->vCard['ADR'])) {
            unset($this->vCard['ADR']);
        }
    }

    private function addADRtoItems()
    {
        foreach ($this->vCard['ADR'] as $ADR) {
            if (in_array('HOME', $ADR['type'])) {
                $this->prepareNewADR('adr_two');
                unset($this->vCard['ADR']['type']['HOME']);
            }
            if (in_array('WORK', $ADR['type'])) {
                $this->prepareNewADR('adr_one');
                unset($this->vCard['ADR']['type']['WORK']);
            }
        }
    }

    private function setTel()
    {
        if (!array_key_exists('TEL', $this->vCard)) {
            $this->addNewDataToVCardArray('TEL', array('tel_cell' => array('CELL', 'VOICE')));
            $this->addNewDataToVCardArray('TEL', array('tel_fax_home' => array('HOME', 'FAX')));
            $this->addNewDataToVCardArray('TEL', array('tel_cell_private' => array('IPHONE', 'CELL', 'VOICE')));
            $this->addNewDataToVCardArray('TEL', array('tel_work' => array('WORK', 'VOICE')));
            $this->addNewDataToVCardArray('TEL', array('tel_fax' => array('WORK', 'FAX')));
            $this->addNewDataToVCardArray('TEL', array('tel_home' => array('HOME', 'VOICE')));
        } else {
            $this->ovewriteData('TEL', array('tel_cell' => array('CELL', 'VOICE')));
            $this->ovewriteData('TEL', array('tel_fax_home' => array('HOME', 'FAX')));
            $this->ovewriteData('TEL', array('tel_cell_private' => array('IPHONE', 'CELL', 'VOICE')));
            $this->ovewriteData('TEL', array('tel_work' => array('WORK', 'VOICE')));
            $this->ovewriteData('TEL', array('tel_fax' => array('WORK', 'FAX')));
            $this->ovewriteData('TEL', array('tel_home' => array('HOME', 'VOICE')));
        }
    }

    private function setSocialProfile()
    {
        if (!array_key_exists('X-SOCIALPROFILE', $this->vCard)) {
            $this->addNewDataToVCardArray('X-SOCIALPROFILE', array('twitter_profile_url' => array('twitter')));
            $this->addNewDataToVCardArray('X-SOCIALPROFILE', array('linkedin_profile_url' => array('linkedin')));
            $this->addNewDataToVCardArray('X-SOCIALPROFILE', array('facebook_profile_url' => array('facebook')));
        } else {
            $this->ovewriteData('X-SOCIALPROFILE', array('twitter_profile_url' => 'twitter'));
            $this->ovewriteData('X-SOCIALPROFILE', array('linkedin_profile_url' => 'linkedin'));
            $this->ovewriteData('X-SOCIALPROFILE', array('facebook_profile_url' => 'facebook'));
        }
    }

    private function setURL()
    {
        if (!array_key_exists('URL', $this->vCard)) {
            $this->addNewDataToVCardArray('URL', array('contact_url' => array('WORK')));
            $this->addNewDataToVCardArray('URL', array('contact_url_home' => array('HOME')));
        } else {
            $this->ovewriteData('URL', array('contact_url' => 'WORK'));
            $this->ovewriteData('URL', array('contact_url_home' => 'HOME'));
        }
    }

    private function setPhoto()
    {
        if ($this->addresses['contact_jpegphoto'] != 1) {
            if (isset($this->vCard['PHOTO'])) {
                unset($this->vCard['PHOTO']);
            }
            return;
        }
        $data = "";
        $size = 460;
        $length = 0;
        $this->addresses->getBinaryField('image_' . $size, $data, $length);
        if (isset($data)) {
            $photo = base64_encode($data);
            $this->checkForPhoto($photo);
        }
    }

    private function checkForPhoto($photo)
    {
        if (!array_key_exists('PHOTO', $this->vCard)) {
            $this->addNewDataToVCardArray('PHOTO', array($photo => array('JPEG')));
        } else {
            $this->ovewriteData('PHOTO', array($photo => 'JPEG'));
        }
    }

    private function setUID()
    {
        if ($this->addresses->contact_uid == '') {
            return $this->addresses->id;
        } else {
            return $this->addresses->contact_uid;
        }
    }

    private function addNewDataToVCardArray($vCardDataName, $addressData)
    {
        $type = array_values($addressData)[0];

        if (isset($this->vCard[$vCardDataName])) {
            array_push($this->vCard[$vCardDataName], array(
                'value' => $this->addresses[key($addressData)],
                'type' => $type,
            ));
        } elseif ($vCardDataName == 'PHOTO') {
            $this->vCard[$vCardDataName]['value'] = key($addressData);
            $this->vCard[$vCardDataName]['type'] = $type;
            $this->vCard[$vCardDataName]['Encoding'] = 'b';
        } else {
            $this->vCard[$vCardDataName] = array(
                array(
                    'value' => $this->addresses[key($addressData)],
                    'type' => $type,
                ),
            );
        }
    }

    private function ovewriteData($vCardDataName, $addressData)
    {
        if (is_array($this->vCard[$vCardDataName])) {
            if (is_array(array_values($addressData)[0])) {
                $this->prepareOverwriteArrayData($vCardDataName, $addressData);
                return;
            }
            if (isset($this->vCard[$vCardDataName]['type'])) {
                $this->overwriteSimpleData($vCardDataName, $addressData);
                return;
            }
            if ($this->overwriteOtherData($vCardDataName, $addressData)) {
                return;
            }

            $this->addDataToArray($vCardDataName, $addressData);
        }
    }

    private function prepareOverwriteArrayData($vCardDataName, $addressData)
    {
        foreach ($this->vCard[$vCardDataName] as $key => $value) {
            if ($this->overwriteArrayData($addressData, $value, $vCardDataName, $key)) {
                return;
            }
        }
        $this->addDataToArray($vCardDataName, $addressData);
    }

    private function overwriteArrayData($addressData, $value, $vCardDataName, $key)
    {
        if (in_array(array_values($addressData)[0][0], $value['type'])) {
            if (in_array(array_values($addressData)[0][1], $value['type'])) {
                $this->vCard[$vCardDataName][$key]['value'] = $this->addresses[key($addressData)];
                return true;
            }
        }
        return false;
    }

    private function overwriteSimpleData($vCardDataName, $addressData)
    {
        if (in_array(array_values($addressData)[0], $this->vCard[$vCardDataName]['type'])) {
            if ($vCardDataName == 'PHOTO') {
                $this->vCard[$vCardDataName]['value'] = key($addressData);
                $this->vCard[$vCardDataName]['Encoding'] = 'b';
            } else {
                $this->vCard[$vCardDataName]['value'] = $this->addresses[key($addressData)];
            }
        }
    }

    private function overwriteOtherData($vCardDataName, $addressData)
    {
        foreach ($this->vCard[$vCardDataName] as $key => $value) {
            if (!isset($value['type'])) {
                continue;
            }
            if (in_array(array_values($addressData)[0], $value['type'])) {
                $this->vCard[$vCardDataName][$key]['value'] = $this->addresses[key($addressData)];
                return true;
            }
        }
        return false;
    }

    private function addDataToArray($vCardDataName, $addressData)
    {
        if (isset($this->addresses[key($addressData)])) {
            if (!is_array(array_values($addressData)[0])) {
                array_push($this->vCard[$vCardDataName], array(
                    'value' => $this->addresses[key($addressData)],
                    'type' => array(array_values($addressData)[0]),
                ));
            } else {
                array_push($this->vCard[$vCardDataName], array(
                    'value' => $this->addresses[key($addressData)],
                    'type' => array_values($addressData)[0],
                ));
            }
        }
    }

    private function prepareDeletionOfEmptyData()
    {
        foreach ($this->vCard as $key => $entry) {
            if ($key != 'N' && is_array($entry)) {
                $this->getEmptyData($entry, $key);
            }
        }
    }

    private function getEmptyData($entry, $key)
    {
        foreach ($entry as $nextKey => $nextEntry) {
            if (!is_array($nextEntry)) {
                return;
            }
            foreach ($nextEntry as $lastEntry) {
                $this->deleteEmptyData($lastEntry, $key, $nextKey);
            }
        }
    }

    private function deleteEmptyData($lastEntry, $key, $nextKey)
    {
        if (empty($lastEntry)) {
            unset($this->vCard[$key][$nextKey]);
        }
    }

    private function validateVCard()
    {
        if (array_key_exists('UID', $this->vCard) && array_key_exists('FN', $this->vCard) && array_key_exists('N', $this->vCard)) {
            if (!empty($this->vCard['UID'])) {
                return true;
            }
        }
        return false;
    }

    private function setAddressUID($addresses)
    {
        if (empty($addresses->contact_uid)) {
            $addresses->contact_uid = $addresses->id;
            if (!$addresses->save()) {
                Log::e('An error has occurred saving addresses model ID-' . @$addresses->id, 'iCloudSync [vCardExporter]');
                Log::e('User-ID: ' . @$addresses->contact_owner, 'iCloudSync [vCardExporter]');
                Log::e('Error Text : ' . json_encode($addresses->errors), 'iCloudSync [vCardExporter]');
            }
        }
    }
}
