/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.settings.datetime.timezone;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.icu.text.DateFormat;
import android.icu.text.SimpleDateFormat;
import android.icu.util.Calendar;
import android.support.annotation.Nullable;

import com.android.settings.R;
import com.android.settings.datetime.timezone.model.TimeZoneData;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

/**
 * Render a list of {@class TimeZoneInfo} into the list view in {@class BaseTimeZonePicker}
 */
public abstract class BaseTimeZoneInfoPicker extends BaseTimeZonePicker {
    protected static final String TAG = "RegionZoneSearchPicker";
    protected ZoneAdapter mAdapter;

    protected BaseTimeZoneInfoPicker(int titleResId, int searchHintResId,
            boolean searchEnabled, boolean defaultExpandSearch) {
        super(titleResId, searchHintResId, searchEnabled, defaultExpandSearch);
    }

    @Override
    protected BaseTimeZoneAdapter createAdapter(TimeZoneData timeZoneData) {
        mAdapter = new ZoneAdapter(getContext(), getAllTimeZoneInfos(timeZoneData),
                this::onListItemClick, getLocale(), getHeaderText());
        return mAdapter;
    }

    /**
     * @return the text shown in the header, or null to show no header.
     */
    protected @Nullable CharSequence getHeaderText() {
        return null;
    }

    private void onListItemClick(TimeZoneInfoItem item) {
        final TimeZoneInfo timeZoneInfo = item.mTimeZoneInfo;
        getActivity().setResult(Activity.RESULT_OK, prepareResultData(timeZoneInfo));
        getActivity().finish();
    }

    protected Intent prepareResultData(TimeZoneInfo selectedTimeZoneInfo) {
        return new Intent().putExtra(EXTRA_RESULT_TIME_ZONE_ID, selectedTimeZoneInfo.getId());
    }

    public abstract List<TimeZoneInfo> getAllTimeZoneInfos(TimeZoneData timeZoneData);

    protected static class ZoneAdapter extends BaseTimeZoneAdapter<TimeZoneInfoItem> {

        public ZoneAdapter(Context context, List<TimeZoneInfo> timeZones,
                OnListItemClickListener<TimeZoneInfoItem> onListItemClickListener, Locale locale,
                CharSequence headerText) {
            super(createTimeZoneInfoItems(context, timeZones, locale),
                    onListItemClickListener, locale,  true /* showItemSummary */,
                    headerText /* headerText */);
        }

        private static List<TimeZoneInfoItem> createTimeZoneInfoItems(Context context,
                List<TimeZoneInfo> timeZones, Locale locale) {
            final DateFormat currentTimeFormat = new SimpleDateFormat(
                    android.text.format.DateFormat.getTimeFormatString(context), locale);
            final ArrayList<TimeZoneInfoItem> results = new ArrayList<>(timeZones.size());
            final Resources resources = context.getResources();
            long i = 0;
            for (TimeZoneInfo timeZone : timeZones) {
                results.add(new TimeZoneInfoItem(i++, timeZone, resources, currentTimeFormat));
            }
            return results;
        }
    }

    private static class TimeZoneInfoItem implements BaseTimeZoneAdapter.AdapterItem {
        private final long mItemId;
        private final TimeZoneInfo mTimeZoneInfo;
        private final Resources mResources;
        private final DateFormat mTimeFormat;
        private final String mTitle;
        private final String[] mSearchKeys;

        private TimeZoneInfoItem(long itemId, TimeZoneInfo timeZoneInfo, Resources resources,
                DateFormat timeFormat) {
            mItemId = itemId;
            mTimeZoneInfo = timeZoneInfo;
            mResources = resources;
            mTimeFormat = timeFormat;
            mTitle = createTitle(timeZoneInfo);
            mSearchKeys = new String[] { mTitle };
        }

        private static String createTitle(TimeZoneInfo timeZoneInfo) {
            String name = timeZoneInfo.getExemplarLocation();
            if (name == null) {
                name = timeZoneInfo.getGenericName();
            }
            if (name == null && timeZoneInfo.getTimeZone().inDaylightTime(new Date())) {
                name = timeZoneInfo.getDaylightName();
            }
            if (name == null) {
                name = timeZoneInfo.getStandardName();
            }
            if (name == null) {
                name = String.valueOf(timeZoneInfo.getGmtOffset());
            }
            return name;
        }

        @Override
        public CharSequence getTitle() {
            return mTitle;
        }

        @Override
        public CharSequence getSummary() {
            String name = mTimeZoneInfo.getGenericName();
            if (name == null) {
                if (mTimeZoneInfo.getTimeZone().inDaylightTime(new Date())) {
                    name = mTimeZoneInfo.getDaylightName();
                } else {
                    name = mTimeZoneInfo.getStandardName();
                }
            }

            // Ignore name / GMT offset if the title shows the same information
            if (name == null || name.equals(mTitle)) {
                CharSequence gmtOffset = mTimeZoneInfo.getGmtOffset();
                return gmtOffset == null || gmtOffset.toString().equals(mTitle) ? "" : gmtOffset;
            } else {
                return SpannableUtil.getResourcesText(mResources,
                        R.string.zone_info_offset_and_name, mTimeZoneInfo.getGmtOffset(), name);
            }
        }

        @Override
        public String getIconText() {
            return null;
        }

        @Override
        public String getCurrentTime() {
            return mTimeFormat.format(Calendar.getInstance(mTimeZoneInfo.getTimeZone()));
        }

        @Override
        public long getItemId() {
            return mItemId;
        }

        @Override
        public String[] getSearchKeys() {
            return mSearchKeys;
        }
    }
}
