package ru.yandex.webmaster3.core.semantic.review_business.biz.model;

import org.json.JSONException;
import ru.yandex.webmaster3.core.semantic.review_business.ModelUtils;
import ru.yandex.webmaster3.core.semantic.review_business.biz.model.impl.json.HCardJsonConversions;

import java.util.Collection;
import java.util.Date;

/**
 * Describes business under review.
 * It has been borrowed from hCard microformat.
 * For details see http://microformats.org/wiki/hcard
 * <p/>
 * Getters of this class are used to count hashCode, so to keep contract (see first point in {@link Object#hashCode()})
 * they should return objects which have same hashCode value during application run time
 * In general - implementation should be immutable and return references which are also immutable
 * <p/>
 *
 * @author Dima Schitinin <dimas@yandex-team.ru>
 */
public abstract class HCard {
    /**
     * @return category of the business. Null signals for off-design state.
     */
    public abstract BizCategory getCategory();

    /**
     * @return generally accepted name of the business
     *         or null if it's inaccessible
     */
    public abstract String getFn();

    /**
     * Alternative names of the business.
     *
     * @return alternative names of the business
     *         or empty collection no alternatives specified
     */
    public abstract Collection<String> getAltNames();

    /**
     * @return addresses of the business
     *         or empty collection if no address specified
     */
    public abstract Collection<Address> getAddresses();

    /**
     * @return URL of business' page in the Web
     *         or null if it's inaccessible
     */
    public abstract String getUrl();

    /**
     * @return URL of business' page on particular resource
     *         or null if it's inaccessible
     */
    public abstract String getLocalUrl();

    /**
     * @return E-mail of the business
     */
    public abstract String getEmail();

    /**
     * @return geographical coordinates
     *         or null if ones are inaccessible
     */
    public abstract Geo getGeo();

    /**
     * @return phone number of business
     *         or null if it's inaccessible
     */
    public abstract String getPhoneNumber();

    /**
     * @return schedule of work
     *         or null if it's inaccessible
     */
    public abstract String getWorkHours();

    /**
     * @return URL of the photo of business
     *         or null if it's inaccessible
     */
    public abstract String getPhotoUrl();

    /**
     * @return log URL of business
     *         or null if it's inaccessible
     */
    public abstract String getLogoUrl();

    /**
     * Features is extension point of information about business.
     * It may contain information about wi-fi existence in the cafe etc.
     * Each feature is pair of name and value.
     * For details see {@link Feature}
     *
     * @return features of the business
     *         or empty collection if we don't know about them
     */
    public abstract Collection<Feature> getFeatures();

    /**
     * @return backa export id of the business. This value is stated by expert (administrator or moderator).
     *         Null if empty
     */
    public abstract Long getBizId();

    public abstract Long getAutoBizId();

    public abstract Collection<Long> getExcludedBizIds();

    public abstract Long getSourceId();

    public abstract Date getWatchTime();

    @Override
    public boolean equals(final Object o) {
        if (this == o) return true;
        if (!(o instanceof HCard)) return false;

        final HCard hCard = (HCard) o;

        return hashCode() == hCard.hashCode()
                && ModelUtils.equals(getFn(), hCard.getFn())
                && ModelUtils.equals(getCategory(), hCard.getCategory())
                && ModelUtils.equals(getAltNames(), hCard.getAltNames())
                && ModelUtils.equals(getAddresses(), hCard.getAddresses())
                && ModelUtils.equals(getUrl(), hCard.getUrl())
                && ModelUtils.equals(getLocalUrl(), hCard.getLocalUrl())
                && ModelUtils.equals(getEmail(), hCard.getEmail())
                && ModelUtils.equals(getPhoneNumber(), hCard.getPhoneNumber())
                && ModelUtils.equals(getWorkHours(), hCard.getWorkHours())
                && ModelUtils.equals(getPhotoUrl(), hCard.getPhotoUrl())
                && ModelUtils.equals(getLogoUrl(), hCard.getLogoUrl())
                && ModelUtils.equals(getFeatures(), hCard.getFeatures())
                && ModelUtils.equals(getBizId(), hCard.getBizId())
                && ModelUtils.equals(getAutoBizId(), hCard.getAutoBizId())
                && ModelUtils.equals(getExcludedBizIds(), hCard.getExcludedBizIds())
                && ModelUtils.equals(getSourceId(), hCard.getSourceId())
                && ModelUtils.equals(getGeo(), hCard.getGeo())
                && ModelUtils.equals(getWatchTime(), hCard.getWatchTime());
    }

    @Override
    public int hashCode() {
        return ModelUtils.hashCode(
                getFn()
                , getCategory()
                , getAltNames()
                , getAddresses()
                , getUrl()
                , getLocalUrl()
                , getEmail()
                , getPhoneNumber()
                , getWorkHours()
                , getPhotoUrl()
                , getLogoUrl()
                , getFeatures()
                , getBizId()
                , getAutoBizId()
                , getExcludedBizIds()
                , getSourceId()
                , getWatchTime()
                , getGeo()
        );
    }

    @Override
    public String toString() {
        try {
            return HCardJsonConversions.toJson(this).toString(1);
        } catch (JSONException e) {
            throw new AssertionError("Not expected to be thrown");
        }
    }
}
