<?php
// Copyright (c) Pickware GmbH. All rights reserved.
// This file is part of software that is released under a proprietary license.
// You must not copy, modify, distribute, make publicly available, or execute
// its contents or parts thereof without express permission by the copyright
// holder, unless otherwise permitted by law.

namespace Shopware\Plugins\ViisonShippingCommon\Classes\Types;

use Shopware\Components\Model\ModelEntity;
use Shopware\Models\Country\Country;
use Shopware\Models\Customer\Address as CustomerAddress;
use Shopware\Models\Customer\Billing as CustomerBilling;
use Shopware\Models\Customer\Shipping as CustomerShipping;
use Shopware\Models\Country\State;
use Shopware\Models\Order\Billing as OrderBilling;
use Shopware\Models\Order\Shipping as OrderShipping;
use Shopware\Plugins\ViisonCommon\Classes\Util\Util;
use VIISON\AddressSplitter\AddressSplitter;
use VIISON\AddressSplitter\Exceptions\SplittingException;

/**
 * Object that represents an address
 */
class Address
{
    /**
     * @var string
     */
    protected $salutation = '';

    /**
     * @var string
     */
    protected $title = '';

    /**
     * @var string
     */
    protected $firstName = '';

    /**
     * @var string
     */
    protected $lastName = '';

    /**
     * @var string
     */
    protected $company = '';

    /**
     * @var string
     */
    protected $department = '';

    /**
     * @var string
     */
    protected $additionOne = '';

    /**
     * @var string
     */
    protected $additionTwo = '';

    /**
     * @var string
     */
    protected $streetName = '';

    /**
     * @var string
     */
    protected $houseNumber = '';

    /**
     * @var string
     */
    protected $houseNumberBase = '';

    /**
     * @var string
     */
    protected $houseNumberExtension = '';

    /**
     * @var string
     */
    protected $zipCode = '';

    /**
     * @var string
     */
    protected $city = '';

    /**
     * @var Country
     */
    protected $country = null;

    /**
     * @var string
     */
    protected $emailAddress = '';

    /**
     * @var string
     */
    protected $phoneNumber = '';

    /**
     * @var string
     */
    protected $region = '';

    /**
     * @var State
     */
    protected $state = null;

    /**
     * @param string $salutation
     */
    public function setSalutation($salutation)
    {
        $this->salutation = $salutation;
    }

    /**
     * @return string
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * @param string $title
     */
    public function setTitle($title)
    {
        $this->title = $title;
    }

    /**
     * @return string
     */
    public function getFirstName()
    {
        return $this->firstName;
    }

    /**
     * @param string $firstName
     */
    public function setFirstName($firstName)
    {
        $this->firstName = $firstName;
    }

    /**
     * @return string
     */
    public function getLastName()
    {
        return $this->lastName;
    }

    /**
     * @param string $lastName
     */
    public function setLastName($lastName)
    {
        $this->lastName = $lastName;
    }

    /**
     * @return string
     */
    public function getCompany()
    {
        return $this->company;
    }

    /**
     * @param string $company
     */
    public function setCompany($company)
    {
        $this->company = $company;
    }

    /**
     * @return string
     */
    public function getDepartment()
    {
        return $this->department;
    }

    /**
     * @param string $department
     */
    public function setDepartment($department)
    {
        $this->department = $department;
    }

    /**
     * @return string
     */
    public function getAdditionOne()
    {
        return $this->additionOne;
    }

    /**
     * @param string $additionOne
     */
    public function setAdditionOne($additionOne)
    {
        $this->additionOne = $additionOne;
    }

    /**
     * @return string
     */
    public function getAdditionTwo()
    {
        return $this->additionTwo;
    }

    /**
     * @param string $additionTwo
     */
    public function setAdditionTwo($additionTwo)
    {
        $this->additionTwo = $additionTwo;
    }

    /**
     * @return string
     */
    public function getStreetName()
    {
        return $this->streetName;
    }

    /**
     * @param string $streetName
     */
    public function setStreetName($streetName)
    {
        $this->streetName = $streetName;
    }

    /**
     * @return string
     */
    public function getHouseNumber()
    {
        return $this->houseNumber;
    }

    /**
     * @param string $houseNumber
     */
    public function setHouseNumber($houseNumber)
    {
        $this->houseNumber = $houseNumber;
    }

    /**
     * @return string
     */
    public function getHouseNumberBase()
    {
        return $this->houseNumberBase;
    }

    /**
     * @param string $houseNumberBase
     */
    public function setHouseNumberBase($houseNumberBase)
    {
        $this->houseNumberBase = $houseNumberBase;
    }

    /**
     * @return string
     */
    public function getHouseNumberExtension()
    {
        return $this->houseNumberExtension;
    }

    /**
     * @param string $houseNumberExtension
     */
    public function setHouseNumberExtension($houseNumberExtension)
    {
        $this->houseNumberExtension = $houseNumberExtension;
    }

    /**
     * @return string
     */
    public function getZipCode()
    {
        return $this->zipCode;
    }

    /**
     * @param string $zipCode
     */
    public function setZipCode($zipCode)
    {
        $this->zipCode = $zipCode;
    }

    /**
     * @return string
     */
    public function getCity()
    {
        return $this->city;
    }

    /**
     * @param string $city
     */
    public function setCity($city)
    {
        $this->city = $city;
    }

    /**
     * @return Country
     */
    public function getCountry()
    {
        return $this->country;
    }

    /**
     * @param Country $country
     */
    public function setCountry(Country $country = null)
    {
        $this->country = $country;
    }

    /**
     * @return string
     */
    public function getEmailAddress()
    {
        return $this->emailAddress;
    }

    /**
     * @param string $emailAddress
     */
    public function setEmailAddress($emailAddress)
    {
        $this->emailAddress = $emailAddress;
    }

    /**
     * @return string
     */
    public function getPhoneNumber()
    {
        return $this->phoneNumber;
    }

    /**
     * @param string $phoneNumber
     */
    public function setPhoneNumber($phoneNumber)
    {
        $this->phoneNumber = $phoneNumber;
    }

    /**
     * @return string
     */
    public function getRegion()
    {
        return $this->region;
    }

    /**
     * @param string $region
     */
    public function setRegion($region)
    {
        $this->region = $region;
    }

    /**
     * @return string
     */
    public function getSalutation()
    {
        return $this->salutation;
    }

    /**
     * @return State
     */
    public function getState()
    {
        return $this->state;
    }

    /**
     * @param State $state
     */
    public function setState(State $state = null)
    {
        $this->state = $state;
    }

    /**
     * Get a string containing address informations
     *
     * @param string $separator
     * @return string
     */
    public function getAddressString($separator = ', ')
    {
        $fullName = join(' ', array_filter(array($this->salutation, $this->title, $this->firstName, $this->lastName)));
        $company = join(', ', array_filter(array($this->company, $this->department)));
        $street = join(' ', array_filter(array($this->streetName, $this->houseNumber, $this->houseNumberBase, $this->houseNumberExtension)));
        $city = join(' ', array_filter(array($this->zipCode, $this->city)));
        $country = join(' ', array_filter(array($this->country ? $this->country->getIsoName() : '', $this->state ? $this->state->getName() : '')));

        $addressParts = array($fullName, $company, $street, $city, $country);
        $addressParts = array_map('trim', $addressParts);
        $addressParts = array_filter($addressParts);

        return join($separator, $addressParts);
    }

    /**
     * @param ModelEntity $addressModel
     * @return Address
     */
    public static function fromShopwareAddress(ModelEntity $addressModel)
    {
        if (!($addressModel instanceof OrderShipping || $addressModel instanceof OrderBilling || $addressModel instanceof CustomerAddress || $addressModel instanceof CustomerBilling || $addressModel instanceof CustomerShipping)) {
            throw new \InvalidArgumentException('$address must be instance of one of Shopware\Models\Order\Billing, Shopware\Models\Order\Shipping or Shopware\Models\Customer\Address');
        }

        $address = new self;

        $address->setSalutation($addressModel->getSalutation());
        $address->setFirstName($addressModel->getFirstName());
        $address->setLastName($addressModel->getLastName());
        $address->setCompany($addressModel->getCompany());
        $address->setDepartment($addressModel->getDepartment());
        $address->setZipCode($addressModel->getZipCode());
        $address->setCity($addressModel->getCity());
        $address->setCountry($addressModel->getCountry());

        if (Util::assertMinimumShopwareVersion('5.2')) {
            // Title only available since Shopware 5.2
            $address->setTitle($addressModel->getTitle());
        }
        $address->setAdditionOne($addressModel->getAdditionalAddressLine1());
        $address->setAdditionTwo($addressModel->getAdditionalAddressLine2());

        if ($addressModel->getState() && $addressModel->getState()->getId() !== null) {
            // State id might be zero (or another random integer) because the foreign key constraint is missing
            // Example problem: Magnalister inserts DB rows with 0 instead of null
            // Check if this state really exists
            $foundCountries = Shopware()->Db()->fetchAll('SELECT id FROM s_core_countries_states WHERE id = :stateId', array('stateId' => $addressModel->getState()->getId()));
            if (count($foundCountries)) {
                $address->setState($addressModel->getState());
            }
        }

        try {
            $splittedAddress = AddressSplitter::splitAddress($addressModel->getStreet());
            $address->setStreetName($splittedAddress['streetName']);
            $address->setHouseNumber($splittedAddress['houseNumber']);
            $address->setHouseNumberBase($splittedAddress['houseNumberParts']['base']);
            $address->setHouseNumberExtension($splittedAddress['houseNumberParts']['extension']);
        } catch (SplittingException $e) {
            $address->setStreetName($addressModel->getStreet());
        }

        if ($addressModel instanceof OrderShipping || $addressModel instanceof OrderBilling || $addressModel instanceof CustomerAddress || $addressModel instanceof CustomerBilling) {
            $address->setPhoneNumber($addressModel->getPhone());
        }

        return $address;
    }
}
