/*
 * Project:  NextGIS Mobile
 * Purpose:  Mobile GIS for Android.
 * Author:   Dmitry Baryshnikov (aka Bishop), [email protected]
 * Author:   NikitaFeodonit, [email protected]
 * Author:   Stanislav Petriakov, [email protected]
 * *****************************************************************************
 * Copyright (c) 2015-2020 NextGIS, [email protected]
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser Public License for more details.
 *
 * You should have received a copy of the GNU Lesser Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.nextgis.maplibui.activity;

import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.database.Cursor;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.provider.SyncStateContract;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.AlertDialog;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.Toast;

import com.nextgis.maplib.datasource.Feature;
import com.nextgis.maplib.datasource.Field;
import com.nextgis.maplib.datasource.GeoGeometry;
import com.nextgis.maplib.datasource.GeoMultiPoint;
import com.nextgis.maplib.datasource.GeoPoint;
import com.nextgis.maplib.map.NGWVectorLayer;
import com.nextgis.maplib.map.VectorLayer;
import com.nextgis.maplib.util.FileUtil;
import com.nextgis.maplib.util.GeoConstants;
import com.nextgis.maplibui.R;
import com.nextgis.maplibui.api.IControl;
import com.nextgis.maplibui.api.IFormControl;
import com.nextgis.maplibui.control.PhotoGallery;
import com.nextgis.maplibui.formcontrol.AutoTextEdit;
import com.nextgis.maplibui.formcontrol.Averaging;
import com.nextgis.maplibui.formcontrol.Checkbox;
import com.nextgis.maplibui.formcontrol.Combobox;
import com.nextgis.maplibui.formcontrol.Coordinates;
import com.nextgis.maplibui.formcontrol.Counter;
import com.nextgis.maplibui.formcontrol.DateTime;
import com.nextgis.maplibui.formcontrol.Distance;
import com.nextgis.maplibui.formcontrol.DoubleCombobox;
import com.nextgis.maplibui.formcontrol.DoubleComboboxValue;
import com.nextgis.maplibui.formcontrol.RadioGroup;
import com.nextgis.maplibui.formcontrol.Sign;
import com.nextgis.maplibui.formcontrol.Space;
import com.nextgis.maplibui.formcontrol.SplitCombobox;
import com.nextgis.maplibui.formcontrol.Tabs;
import com.nextgis.maplibui.formcontrol.TextEdit;
import com.nextgis.maplibui.formcontrol.TextLabel;
import com.nextgis.maplibui.util.ControlHelper;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import static com.nextgis.maplib.util.Constants.JSON_TYPE_KEY;
import static com.nextgis.maplibui.util.ConstantsUI.JSON_ALBUM_ELEMENTS_KEY;
import static com.nextgis.maplibui.util.ConstantsUI.JSON_ATTRIBUTES_KEY;
import static com.nextgis.maplibui.util.ConstantsUI.JSON_AVERAGING_VALUE;
import static com.nextgis.maplibui.util.ConstantsUI.JSON_CHECKBOX_VALUE;
import static com.nextgis.maplibui.util.ConstantsUI.JSON_COMBOBOX_VALUE;
import static com.nextgis.maplibui.util.ConstantsUI.JSON_COORDINATES_VALUE;
import static com.nextgis.maplibui.util.ConstantsUI.JSON_COUNTER_VALUE;
import static com.nextgis.maplibui.util.ConstantsUI.JSON_DATE_TIME_VALUE;
import static com.nextgis.maplibui.util.ConstantsUI.JSON_DISTANCE_VALUE;
import static com.nextgis.maplibui.util.ConstantsUI.JSON_DOUBLE_COMBOBOX_VALUE;
import static com.nextgis.maplibui.util.ConstantsUI.JSON_FIELD_NAME_KEY;
import static com.nextgis.maplibui.util.ConstantsUI.JSON_KEY_LIST_KEY;
import static com.nextgis.maplibui.util.ConstantsUI.JSON_KEY_LIST_SAVED_KEY;
import static com.nextgis.maplibui.util.ConstantsUI.JSON_LISTS_KEY;
import static com.nextgis.maplibui.util.ConstantsUI.JSON_PHOTO_VALUE;
import static com.nextgis.maplibui.util.ConstantsUI.JSON_PORTRAIT_ELEMENTS_KEY;
import static com.nextgis.maplibui.util.ConstantsUI.JSON_RADIO_GROUP_VALUE;
import static com.nextgis.maplibui.util.ConstantsUI.JSON_SIGN_VALUE;
import static com.nextgis.maplibui.util.ConstantsUI.JSON_SPACE_VALUE;
import static com.nextgis.maplibui.util.ConstantsUI.JSON_SPLIT_COMBOBOX_VALUE;
import static com.nextgis.maplibui.util.ConstantsUI.JSON_TABS_KEY;
import static com.nextgis.maplibui.util.ConstantsUI.JSON_TEXT_EDIT_VALUE;
import static com.nextgis.maplibui.util.ConstantsUI.JSON_TEXT_LABEL_VALUE;
import static com.nextgis.maplibui.util.ConstantsUI.JSON_TRANSLATIONS_KEY;
import static com.nextgis.maplibui.util.ConstantsUI.KEY_FORM_PATH;
import static com.nextgis.maplibui.util.ConstantsUI.KEY_META_PATH;
import static com.nextgis.maplibui.util.NGIDUtils.PREF_FIRST_NAME;
import static com.nextgis.maplibui.util.NGIDUtils.PREF_LAST_NAME;
import static com.nextgis.maplibui.util.NGIDUtils.PREF_USERNAME;

/**
 * Activity to add or modify vector layer attributes
 */
public class FormBuilderModifyAttributesActivity extends ModifyAttributesActivity {
    private static final int RESELECT_ROW = 999;

    private Map<String, List<String>> mTable;
    private Map<String, Map<String, String>> mTranslations;
    private int mRow = -1;
    private File mMeta;
    private String mColumn;

    interface OnAskRowListener {
        void onRowChosen();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);

        if (mColumn != null) {
            MenuItem apply = menu.add(0, RESELECT_ROW, 50, R.string.select_row);
            apply.setIcon(R.drawable.ic_altitude);
            MenuItemCompat.setShowAsAction(apply, MenuItemCompat.SHOW_AS_ACTION_ALWAYS);
        }

        if (mIsViewOnly) {
            MenuItem item = menu.findItem(R.id.menu_apply);
            if (item != null)
                item.setVisible(false);
        }

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case RESELECT_ROW:
                if (mMeta != null && mMeta.exists()) {
                    try {
                        String metaString = FileUtil.readFromFile(mMeta);
                        JSONObject metaJson = new JSONObject(metaString);
                        metaJson.remove(JSON_KEY_LIST_SAVED_KEY);
                        FileUtil.writeToFile(mMeta, metaJson.toString());
                        refreshActivityView();
                    } catch (JSONException | IOException ignored) {}
                }
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    @Override
    protected void fillControls(LinearLayout layout, Bundle savedState) {
        //TODO: add location control via fragment only defined by user space
        Bundle extras = getIntent().getExtras();

        if (mTable == null) {
            fillTable(layout, savedState, extras);
            return;
        }

        try {
            File form = (File) extras.getSerializable(KEY_FORM_PATH);

            int orientation = getResources().getConfiguration().orientation;
            boolean isLand = orientation == Configuration.ORIENTATION_LANDSCAPE;

            String formString = FileUtil.readFromFile(form);
            Object json = new JSONTokener(formString).nextValue();
            if (json instanceof JSONArray) {
                JSONArray elements = new JSONArray(formString);
                if (elements.length() > 0)
                    fillTabControls(layout, savedState, elements);
            } else {
                JSONObject jsonFormContents = new JSONObject(formString);
                JSONArray tabs = jsonFormContents.getJSONArray(JSON_TABS_KEY);

                for (int i = 0; i < tabs.length(); i++) {
                    JSONObject tab = tabs.getJSONObject(i);
                    JSONArray elements = null;

                    if (isLand && !tab.isNull(JSON_ALBUM_ELEMENTS_KEY)) {
                        elements = tab.getJSONArray(JSON_ALBUM_ELEMENTS_KEY);
                    }

                    if (null == elements) {
                        if (!isLand && !tab.isNull(JSON_PORTRAIT_ELEMENTS_KEY)) {
                            elements = tab.getJSONArray(JSON_PORTRAIT_ELEMENTS_KEY);
                        }
                    }

                    if (null == elements) {
                        if (!tab.isNull(JSON_ALBUM_ELEMENTS_KEY)) {
                            elements = tab.getJSONArray(JSON_ALBUM_ELEMENTS_KEY);
                        }

                        if (!tab.isNull(JSON_PORTRAIT_ELEMENTS_KEY)) {
                            elements = tab.getJSONArray(JSON_ALBUM_ELEMENTS_KEY);
                        }
                    }

                    if (null != elements && elements.length() > 0) {
                        fillTabControls(layout, savedState, elements);
                    }
                }
            }
        } catch (JSONException | IOException e) {
            e.printStackTrace();
            Toast.makeText(this, getString(R.string.error_form_create), Toast.LENGTH_SHORT).show();
        }
    }

    private void fillTable(final LinearLayout layout, final Bundle savedState, Bundle extras) {
        mTable = new HashMap<>();
        mTranslations = new HashMap<>();
        mMeta = (File) extras.getSerializable(KEY_META_PATH);
        if (mMeta != null && mMeta.exists()) {
            try {
                String metaString = FileUtil.readFromFile(mMeta);
                final JSONObject metaJson = new JSONObject(metaString);
                if (metaJson.has(JSON_LISTS_KEY) && !metaJson.isNull(JSON_LISTS_KEY)) {
                    JSONObject lists = metaJson.getJSONObject(JSON_LISTS_KEY);
                    Iterator<String> i = lists.keys();
                    while (i.hasNext()) {
                        String key = i.next();
                        JSONArray list = lists.getJSONArray(key);
                        List<String> value = new ArrayList<>();
                        for (int j = 0; j < list.length(); j++)
                            value.add(list.getString(j));

                        mTable.put(key, value);
                    }
                }

                if (metaJson.has(JSON_KEY_LIST_KEY) && !metaJson.isNull(JSON_KEY_LIST_KEY)) {
                    mColumn = metaJson.getString(JSON_KEY_LIST_KEY);

                    if (metaJson.has(JSON_KEY_LIST_SAVED_KEY))
                        mRow = metaJson.getInt(JSON_KEY_LIST_SAVED_KEY);
                    else {
                        askForRow(new OnAskRowListener() {
                            @Override
                            public void onRowChosen() {
                                if (mRow == -1)
                                    finish();
                                else {
                                    try {
                                        metaJson.put(JSON_KEY_LIST_SAVED_KEY, mRow);
                                        FileUtil.writeToFile(mMeta, metaJson.toString());
                                    } catch (JSONException | IOException ignored) {}
                                    fillControls(layout, savedState);
                                }
                            }
                        });
                        return;
                    }
                }

                if (metaJson.has(JSON_TRANSLATIONS_KEY) && !metaJson.isNull(JSON_TRANSLATIONS_KEY)) {
                    JSONArray translations = metaJson.getJSONArray(JSON_TRANSLATIONS_KEY);
                    if (translations != null) {
                        for (int i = 0; i < translations.length(); i++) {
                            JSONObject translation = translations.getJSONObject(i);
                            String translationKey = null;
                            Map<String, String> mappings = new HashMap<>();
                            for (Iterator<String> iter = translation.keys(); iter.hasNext(); ) {
                                String key = iter.next();
                                String value = translation.getString(key);
                                if (key.equals("key")) {
                                    translationKey = value;
                                } else {
                                    mappings.put(key, value);
                                }
                            }

                            if (translationKey != null)
                                mTranslations.put(translationKey, mappings);
                        }
                    }
                }
            } catch (IOException | JSONException e) {
                e.printStackTrace();
            }
        }

        fillControls(layout, savedState);
    }

    private void askForRow(final OnAskRowListener listener) {
        ArrayAdapter<String> spinnerMenu = new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, mTable.get(mColumn));
        final Spinner spinner = (Spinner) View.inflate(this, R.layout.table_select_row, null);
        spinner.setAdapter(spinnerMenu);

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(R.string.select_row).setView(spinner)
               .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                   @Override
                   public void onClick(DialogInterface dialog, int which) {
                       mRow = spinner.getSelectedItemPosition();
                   }
               })
               .setOnDismissListener(new DialogInterface.OnDismissListener() {
                   @Override
                   public void onDismiss(DialogInterface dialogInterface) {
                       listener.onRowChosen();
                   }
               });
        AlertDialog dialog = builder.show();
        dialog.setCanceledOnTouchOutside(false);
    }

    private void setViewOnly(String author) {
        String fName = mPreferences.getString(PREF_FIRST_NAME, "");
        String lName = mPreferences.getString(PREF_LAST_NAME, "");
        String uName = mPreferences.getString(PREF_USERNAME, "");
        String name = TextEdit.formUserName(fName, lName, uName);
        mIsViewOnly = mIsViewOnly || !author.equals(name);
    }

    @Override
    protected Cursor getFeatureCursor() {
        Cursor featureCursor = super.getFeatureCursor();
        if (featureCursor != null) {
            Feature feature = mLayer.getFeature(mFeatureId);
            List<Field> fields = feature.getFields();
            for (Field field : fields) {
                if (field.getAlias().toLowerCase().equals("author")) {
                    String author = feature.getFieldValueAsString(field.getName());
                    setViewOnly(author);
                    return featureCursor;
                }
            }
            int id = featureCursor.getColumnIndex("author");
            if (id >= 0) {
                try {
                    String author = featureCursor.getString(id);
                    setViewOnly(author);
                } catch (Exception ignored) {}
            }
        }
        return featureCursor;
    }

    protected void fillTabControls(
            LinearLayout layout,
            Bundle savedState,
            JSONArray elements)
            throws JSONException {

        Cursor featureCursor = getFeatureCursor();
        List<Field> fields = mLayer.getFields();
        for (int i = 0; i < elements.length(); i++) {
            IFormControl control;
            JSONObject element = elements.getJSONObject(i);
            String type = element.optString(JSON_TYPE_KEY);
            if (type.equals(JSON_COORDINATES_VALUE)) {
                JSONObject attributes = element.getJSONObject(JSON_ATTRIBUTES_KEY);
                String fieldY = attributes.optString(JSON_FIELD_NAME_KEY + "_lat");
                attributes.put(JSON_FIELD_NAME_KEY, fieldY);
                element.put(JSON_TYPE_KEY, type + "_lat");
                control = getControl(this, element, mLayer, mFeatureId, mGeometry, mIsViewOnly);
                addToLayout(control, element, fields, savedState, featureCursor, layout);

                attributes = element.getJSONObject(JSON_ATTRIBUTES_KEY);
                String fieldX = attributes.optString(JSON_FIELD_NAME_KEY + "_long");
                attributes.put(JSON_FIELD_NAME_KEY, fieldX);
                element.put(JSON_TYPE_KEY, type + "_lon");
            }

            control = getControl(this, element, mLayer, mFeatureId, mGeometry, mIsViewOnly);
            if (type.equals(JSON_TABS_KEY))
                ((Tabs) control).init(mLayer, mFeatureId, mGeometry, mTable, mRow, mSharedPreferences,
                                      mPreferences, getSupportFragmentManager(), mIsViewOnly);

            addToLayout(control, element, fields, savedState, featureCursor, layout);
        }

        if (null != featureCursor) {
            featureCursor.close();
        }

        layout.requestLayout();
    }

    public static IFormControl getControl(Context context, JSONObject element, VectorLayer layer, long feature,
                                          GeoGeometry geometry, boolean isViewOnly) throws JSONException {
        String type = element.getString(JSON_TYPE_KEY);
        IFormControl control = null;

        switch (type) {
            case JSON_TEXT_LABEL_VALUE:
                control = (TextLabel) View.inflate(context, R.layout.formtemplate_textlabel, null);
                break;

            case JSON_TEXT_EDIT_VALUE:
                control = (TextEdit) View.inflate(context, R.layout.formtemplate_edittext, null);
                break;

            case JSON_DATE_TIME_VALUE:
                control = (DateTime) View.inflate(context, R.layout.formtemplate_datetime, null);
                break;

            case JSON_RADIO_GROUP_VALUE:
                control = (RadioGroup) View.inflate(context, R.layout.formtemplate_radiogroup, null);
                break;

            case JSON_COMBOBOX_VALUE:
                if (ControlHelper.isAutoComplete(element.getJSONObject(JSON_ATTRIBUTES_KEY)))
                    control = (AutoTextEdit) View.inflate(context, R.layout.formtemplate_autoedittext, null);
                else
                    control = (Combobox) View.inflate(context, R.layout.formtemplate_combobox, null);
                break;

            case JSON_SPLIT_COMBOBOX_VALUE:
                control = new SplitCombobox(context);
                break;

            case JSON_DOUBLE_COMBOBOX_VALUE:
                control = (DoubleCombobox) View.inflate(context, R.layout.formtemplate_doublecombobox, null);
                break;

            case JSON_SPACE_VALUE:
                control = (Space) View.inflate(context, R.layout.formtemplate_space, null);
                break;

            case JSON_CHECKBOX_VALUE:
                control = (Checkbox) View.inflate(context, R.layout.formtemplate_checkbox, null);
                break;

            case JSON_AVERAGING_VALUE:
                control = (Averaging) View.inflate(context, R.layout.formtemplate_averaging, null);
                break;

            case JSON_PHOTO_VALUE:
                if (isViewOnly)
                    control = (PhotoGallery) View.inflate(context, R.layout.formtemplate_photo_disabled, null);
                else
                    control = (PhotoGallery) View.inflate(context, R.layout.formtemplate_photo, null);
                ((PhotoGallery) control).init(layer, feature);
                break;

            case JSON_SIGN_VALUE:
                control = (Sign) View.inflate(context, R.layout.formtemplate_sign, null);
                ((Sign) control).setPath(layer.getPath().getPath() + File.separator + feature);
                break;

            case JSON_COUNTER_VALUE:
                control = (Counter) View.inflate(context, R.layout.formtemplate_counter, null);
                break;

            case JSON_DISTANCE_VALUE:
                control = (Distance) View.inflate(context, R.layout.formtemplate_distance, null);
                if (geometry instanceof GeoPoint || geometry instanceof GeoMultiPoint) {
                    GeoPoint point;
                    if (geometry instanceof GeoMultiPoint)
                        point = (GeoPoint) ((GeoMultiPoint) geometry).get(0).copy();
                    else
                        point = (GeoPoint) geometry.copy();
                    point.setCRS(GeoConstants.CRS_WEB_MERCATOR);
                    point.project(GeoConstants.CRS_WGS84);
                    Location location = new Location(LocationManager.GPS_PROVIDER);
                    location.setLatitude(point.getY());
                    location.setLongitude(point.getX());
                    ((Distance) control).setLocation(location);
                }
                break;

            case JSON_COORDINATES_VALUE + "_lon":
                Double x = getCoordinate(geometry, false);
                control = (Coordinates) View.inflate(context, R.layout.formtemplate_coordinates, null);
                if (control != null) {
                    if (x != null)
                        ((Coordinates) control).setValue(x);
                    if (!(geometry instanceof GeoPoint) && !(geometry instanceof GeoMultiPoint))
                        ((Coordinates) control).setVisibility(View.GONE);
                }
                break;

            case JSON_COORDINATES_VALUE + "_lat":
                Double y = getCoordinate(geometry, true);
                control = (Coordinates) View.inflate(context, R.layout.formtemplate_coordinates, null);
                if (control != null) {
                    ((Coordinates) control).setIsLat();
                    if (y != null)
                        ((Coordinates) control).setValue(y);
                    if (!(geometry instanceof GeoPoint) && !(geometry instanceof GeoMultiPoint))
                        ((Coordinates) control).setVisibility(View.GONE);
                }
                break;

            case JSON_TABS_KEY:
                control = (Tabs) View.inflate(context, R.layout.formtemplate_tabs, null);
                break;

            //TODO: add controls
            //button
            //group
            //orientation
            //compass

            default:
                break;
        }

        return control;
    }

    protected static Double getCoordinate(GeoGeometry geometry, boolean latitude) {
        double x, y;
        x = y = Double.NaN;
        GeoPoint point = null;
        if (geometry instanceof GeoPoint) {
            point = (GeoPoint) geometry.copy();
        }
        if (geometry instanceof GeoMultiPoint) {
            point = ((GeoMultiPoint) geometry.copy()).get(0);
        }

        if (point != null) {
            point.setCRS(GeoConstants.CRS_WEB_MERCATOR);
            point.project(GeoConstants.CRS_WGS84);
            y = point.getY();
            x = point.getX();
        }

        return latitude ? y : x;
    }

    @Override
    protected void setLocationText(Location location) {
        super.setLocationText(location);
        for (Map.Entry<String, IControl> control : mFields.entrySet()) {
            IControl current = control.getValue();
            if (current instanceof Coordinates) {
                double lat = location == null ? 0 : location.getLatitude();
                double lon = location == null ? 0 : location.getLongitude();
                ((Coordinates) current).setValue(((Coordinates) current).isLat() ? lat : lon);
                ((Coordinates) current).setText(((Coordinates) current).getFormattedValue());
            }
        }
    }

    protected void addToLayout(IFormControl control, JSONObject element, List<Field> fields, Bundle savedState,
                               Cursor featureCursor, LinearLayout layout) throws JSONException {
        if (null != control) {
            appendData(mLayer, mPreferences, mTable, mRow, control, element);

            control.init(element, fields, savedState, featureCursor, mSharedPreferences, mTranslations);
            control.addToLayout(layout);
            if (mIsViewOnly)
                control.setEnabled(false);

            String fieldName = control.getFieldName();
            if (null != fieldName)
                mFields.put(fieldName, control);
            if (control instanceof Tabs) {
                Tabs tabs = (Tabs) control;
                mFields.putAll(tabs.getFields());
            }
        }
    }

    public static void appendData(VectorLayer layer, SharedPreferences preferences, Map<String, List<String>> table, int row,
                                  IFormControl control, JSONObject element) throws JSONException {
        if (layer instanceof NGWVectorLayer)
            element.put(SyncStateContract.Columns.ACCOUNT_NAME, ((NGWVectorLayer) layer).getAccountName());

        if (preferences != null) {
            element.put(PREF_FIRST_NAME, preferences.getString(PREF_FIRST_NAME, ""));
            element.put(PREF_LAST_NAME, preferences.getString(PREF_LAST_NAME, ""));
            element.put(PREF_USERNAME, preferences.getString(PREF_USERNAME, ""));
        }

        if (control instanceof Counter && table != null && row != -1) {
            JSONObject attrs = element.getJSONObject(JSON_ATTRIBUTES_KEY);
            if (!attrs.isNull(Counter.PREFIX_LIST)) {
                String prefix = attrs.getString(Counter.PREFIX_LIST);
                prefix = table.get(prefix).get(row);
                attrs.put(Counter.PREFIX, prefix);
            }

            if (!attrs.isNull(Counter.SUFFIX_LIST)) {
                String suffix = attrs.getString(Counter.SUFFIX_LIST);
                suffix = table.get(suffix).get(row);
                attrs.put(Counter.SUFFIX, suffix);
            }
        }
    }

    @Override
    protected boolean saveFeature() {
        boolean success = super.saveFeature();
        if (success)
            for (Field field : mLayer.getFields())
                saveLastValue(field);

        return success;
    }

    protected Object putFieldValue(ContentValues values, Field field) {
        Object value = super.putFieldValue(values, field);
        IFormControl control = (IFormControl) mFields.get(field.getName());
        if (null == control)
            return null;

        if (null != value) {
            if (value instanceof DoubleComboboxValue) {
                DoubleComboboxValue dcValue = (DoubleComboboxValue) value;
                values.put(dcValue.mFieldName, dcValue.mValue);
                values.put(dcValue.mSubFieldName, dcValue.mSubValue);
            }
        }

        return value;
    }

    protected void saveLastValue(Field field) {
        IFormControl control = (IFormControl) mFields.get(field.getName());
        if (null != control && control.isShowLast())
            control.saveLastValue(mSharedPreferences);
    }
}