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

import com.google.common.base.Preconditions;
import com.google.common.collect.Collections2;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.yandex.webmaster3.core.semantic.review_business.biz.model.*;
import ru.yandex.webmaster3.core.semantic.review_business.util.DateHelper;
import ru.yandex.webmaster3.core.semantic.review_business.util.JsonAccessUtils;

import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashSet;

import static com.google.common.base.Strings.emptyToNull;
import static ru.yandex.webmaster3.core.semantic.review_business.biz.model.impl.HCardAttributes.*;

/**
 * TODO
 *
 * @author Dima Schitinin <dimas@yandex-team.ru>
 */
public class HCardOverJson extends HCard {

    private static final Logger log = LoggerFactory.getLogger(HCardOverJson.class);

    private final JSONObject json;

    /**
     * This implementation breaks the contract for hashCode (because hashCode is counted
     * on top of all get methods of Object and JSONObject is mutable and cannot be controlled from
     * this implementation)
     * Visibility will be changed to package private (in case of necessity
     * of usage in constructing of high-level objects) or removed completely
     */
    @Deprecated
    public HCardOverJson(final JSONObject json) {
        Preconditions.checkNotNull(json, "Unable to create HCard over null JSON");
        this.json = json;
    }

    public HCardOverJson(final String json) throws JSONException {
        Preconditions.checkNotNull(emptyToNull(json), "Unable to create HCard over empty JSON string");
        this.json = new JSONObject(json);
    }
    @Override
    public BizCategory getCategory() {
        return BizCategory.byName(json.optString(CATEGORY, null), null);
    }

    @Override
    public String getFn() {
        return json.optString(FN, null);
    }

    @Override
    public Collection<String> getAltNames() {
        try {
            return JsonAccessUtils.arrayToStrings(json.optJSONArray(ALTNAMES));
        } catch (JSONException e) {
            log.error("Error while getting alt names from JSON", e);
            return Collections.emptyList();
        }
    }

    @Override
    public Collection<Address> getAddresses() {
        try {
            return Collections2.transform(
                    JsonAccessUtils.arrayToJsons(json.optJSONArray(ADRS)),
                    AddressJsonConversions.JSON_TO_ADDRESS);
        } catch (JSONException e) {
            log.error("Error while getting addresses from JSON", e);
            return Collections.emptyList();
        }
    }

    @Override
    public String getUrl() {
        return json.optString(URL, null);
    }

    @Override
    public String getLocalUrl() {
        return json.optString(LOCALURL, null);
    }

    @Override
    public String getEmail() {
        return json.optString(EMAIL, null);
    }

    @Override
    public Geo getGeo() {
        try {
            if (json.optJSONObject(GEO) == null)
                return null;
            return new GeoOverJson(json.optJSONObject(GEO).toString());
        } catch (JSONException e) {
            log.error("Problems while converting json to geo.");
            return null;
        }
    }

    @Override
    public String getPhoneNumber() {
        return json.optString(TEL, null);
    }

    @Override
    public String getWorkHours() {
        return json.optString(WORKHOURS, null);
    }

    @Override
    public String getPhotoUrl() {
        return json.optString(PHOTO, null);
    }

    @Override
    public String getLogoUrl() {
        return json.optString(LOGO, null);
    }

    @Override
    public Collection<Feature> getFeatures() {
        try {
            return Collections2.transform(
                    JsonAccessUtils.arrayToJsons(json.optJSONArray(FEATURES)),
                    FeatureJsonConversions.JSON_TO_FEATURE);
        } catch (JSONException e) {
            log.error("Error while getting features from JSON", e);
            return Collections.emptyList();
        }
    }

    @Override
    public Long getBizId() {
        return JsonAccessUtils.optLong(json, BIZ_ID);
    }

    @Override
    public Long getAutoBizId() {
        return JsonAccessUtils.optLong(json, AUTO_BIZ_ID);
    }

    @Override
    public Collection<Long> getExcludedBizIds() {
        JSONArray array = json.optJSONArray(EXCLUDED_BIZ_IDS);
        return array != null ?
                new LinkedHashSet<Long>(JsonAccessUtils.arrayToLongs(array)) :
                Collections.<Long>emptyList();
    }

    @Override
    public Long getSourceId() {
        return JsonAccessUtils.optLong(json, SOURCE_ID);
    }

    @Override
    public Date getWatchTime() {
        return DateHelper.read(json.optString(WATCH_TIME));
    }
}

