package com.yoshione.fingen;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.TimePickerDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.constraint.ConstraintLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.TabLayout;
import android.support.design.widget.TextInputLayout;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.Editable;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextWatcher;
import android.text.style.BackgroundColorSpan;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.crashlytics.android.Crashlytics;
import com.yoshione.fingen.adapter.AdapterProducts;
import com.yoshione.fingen.adapter.NestedItemFullNameAdapter;
import com.yoshione.fingen.dao.AccountsDAO;
import com.yoshione.fingen.dao.CategoriesDAO;
import com.yoshione.fingen.dao.DepartmentsDAO;
import com.yoshione.fingen.dao.LocationsDAO;
import com.yoshione.fingen.dao.PayeesDAO;
import com.yoshione.fingen.dao.ProjectsDAO;
import com.yoshione.fingen.dao.SimpleDebtsDAO;
import com.yoshione.fingen.dao.SmsDAO;
import com.yoshione.fingen.dao.SmsMarkersDAO;
import com.yoshione.fingen.dao.TemplatesDAO;
import com.yoshione.fingen.dao.TransactionsDAO;
import com.yoshione.fingen.fts.ActivityFtsLogin;
import com.yoshione.fingen.fts.ActivityScanQR;
import com.yoshione.fingen.fts.FtsHelper;
import com.yoshione.fingen.fts.IDownloadProductsListener;
import com.yoshione.fingen.interfaces.IAbstractModel;
import com.yoshione.fingen.managers.AccountManager;
import com.yoshione.fingen.managers.PayeeManager;
import com.yoshione.fingen.managers.SmsMarkerManager;
import com.yoshione.fingen.managers.TransactionManager;
import com.yoshione.fingen.managers.TransferManager;
import com.yoshione.fingen.managers.TreeManager;
import com.yoshione.fingen.model.Account;
import com.yoshione.fingen.model.AutocompleteItem;
import com.yoshione.fingen.model.Cabbage;
import com.yoshione.fingen.model.Category;
import com.yoshione.fingen.model.Credit;
import com.yoshione.fingen.model.Location;
import com.yoshione.fingen.model.Payee;
import com.yoshione.fingen.model.ProductEntry;
import com.yoshione.fingen.model.Sms;
import com.yoshione.fingen.model.SmsMarker;
import com.yoshione.fingen.model.Template;
import com.yoshione.fingen.model.TrEditItem;
import com.yoshione.fingen.model.Transaction;
import com.yoshione.fingen.receivers.SMSReceiver;
import com.yoshione.fingen.utils.BaseNode;
import com.yoshione.fingen.utils.CabbageFormatter;
import com.yoshione.fingen.utils.DateTimeFormatter;
import com.yoshione.fingen.utils.FabMenuController;
import com.yoshione.fingen.utils.NotificationCounter;
import com.yoshione.fingen.utils.NotificationHelper;
import com.yoshione.fingen.utils.PrefUtils;
import com.yoshione.fingen.utils.RequestCodes;
import com.yoshione.fingen.utils.SmartFragmentStatePagerAdapter;
import com.yoshione.fingen.utils.SmsParser;
import com.yoshione.fingen.utils.SwipeDetector;
import com.yoshione.fingen.widgets.AmountEditor;
import com.yoshione.fingen.widgets.MyViewPager;
import com.yoshione.fingen.widgets.SmsEditText;
import com.yoshione.fingen.widgets.ToolbarActivity;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.inject.Inject;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import io.fabric.sdk.android.Fabric;
import permissions.dispatcher.NeedsPermission;
import permissions.dispatcher.OnNeverAskAgain;
import permissions.dispatcher.OnPermissionDenied;
import permissions.dispatcher.OnShowRationale;
import permissions.dispatcher.PermissionRequest;
import permissions.dispatcher.RuntimePermissions;
import uk.co.deanwild.materialshowcaseview.MaterialShowcaseSequence;
import uk.co.deanwild.materialshowcaseview.MaterialShowcaseView;
import uk.co.deanwild.materialshowcaseview.ShowcaseConfig;

import static com.yoshione.fingen.utils.RequestCodes.REQUEST_CODE_SELECT_MODEL;
import static com.yoshione.fingen.utils.RequestCodes.REQUEST_CODE_SELECT_MODEL_FOR_PRODUCT;

/**
 * Created by slv on 20.08.2015.
 * a
 */
@RuntimePermissions
public class ActivityEditTransaction extends ToolbarActivity implements
        FragmentDestAccount.FragmentDestAccountListener,
        FragmentPayee.FragmentPayeeListener{

    //<editor-fold desc="Static declarations" defaultstate="collapsed">
    private static final int FRAGMENT_PAYEE = 0;
    private static final int FRAGMENT_DEST_ACCOUNT = 1;
    private static final int ERR_EXRATE_ZERO = 1;
    private static final int ERR_EXRATE_ONE = 2;
    private static final int ERR_EMPTY_SRC_ACCOUNT = 3;
    private static final String SHOWCASE_ID = "Edit transaction showcase";
    //</editor-fold>

    //<editor-fold desc="Bind views" defaultstate="collapsed">
    @BindView(R.id.te_lay_DateTime)
    LinearLayout teLayDateTime;
    @BindView(R.id.editTextTemplateName)
    EditText editTextTemplateName;
    @BindView(R.id.layoutCategory)
    RelativeLayout layoutCategory;
    @BindView(R.id.layoutSms)
    RelativeLayout layoutSms;
    @BindView(R.id.layoutProject)
    RelativeLayout layoutProject;
    @BindView(R.id.layoutLocation)
    RelativeLayout layoutLocation;
    @BindView(R.id.textViewSrcAmount)
    EditText textViewSrcAmount;
    @BindView(R.id.textViewDepartment)
    EditText edDepartment;
    @BindView(R.id.imageButtonDeleteDepartment)
    ImageButton imageButtonDeleteDepartment;
    @BindView(R.id.layoutDepartment)
    RelativeLayout layoutDepartment;
    @BindView(R.id.textViewSimpleDebt)
    EditText mTextViewSimpleDebt;
    @BindView(R.id.imageButtonDeleteDebt)
    ImageButton mImageButtonDeleteDebt;
    @BindView(R.id.layoutSimpleDebt)
    RelativeLayout layoutSimpleDebt;
    @BindView(R.id.buttonMore)
    Button mButtonMore;
    @BindView(R.id.textInputLayoutTemplateName)
    TextInputLayout mTextInputLayoutTemplateName;
    @BindView(R.id.textInputLayoutSrcAmount)
    TextInputLayout mTextInputLayoutSrcAmount;
    @BindView(R.id.textInputLayoutExchangeRate)
    TextInputLayout mTextInputLayoutExchangeRate;
    @BindView(R.id.te_pager_payee)
    MyViewPager viewPager;
    @BindView(R.id.textInputLayoutAccount)
    TextInputLayout textInputLayoutAccount;
    @BindView(R.id.textViewAccount)
    EditText textViewAccount;
    @BindView(R.id.textViewCategory)
    EditText edCategory;
    @BindView(R.id.textViewProject)
    EditText edProject;
    @BindView(R.id.textViewLocation)
    EditText edLocation;
    @BindView(R.id.editTextDate)
    EditText edDate;
    @BindView(R.id.te_ed_Time)
    EditText edTime;
    @BindView(R.id.edit_text_exchange_rate)
    EditText edExchangeRate;
    @BindView(R.id.editTextComment)
    EditText edComment;
    @BindView(R.id.te_tv_sms)
    SmsEditText edSms;
    @BindView(R.id.amount_editor)
    AmountEditor amountEditor;
    @BindView(R.id.dest_amount_editor)
    AmountEditor destAmountEditor;
    @BindView(R.id.imageButtonDeleteLocation)
    ImageButton imageButtonDeleteLocation;
    @BindView(R.id.imageButtonDeleteCategory)
    ImageButton imageButtonDeleteCategory;
    @BindView(R.id.imageButtonDeleteProject)
    ImageButton imageButtonDeleteProject;
    @BindView(R.id.imageButtonAddMarker)
    ImageButton imageButtonAddMarker;
    @BindView(R.id.tabLayoutType)
    TabLayout tabLayoutType;
    @BindView(R.id.textViewFN)
    EditText mTextViewFN;
    @BindView(R.id.textViewFD)
    EditText mTextViewFD;
    @BindView(R.id.textViewFP)
    EditText mTextViewFP;
    @BindView(R.id.imageButtonDownloadReceipt)
    ImageButton mImageButtonDownloadReceipt;
    @BindView(R.id.imageButtonScanQR)
    ImageButton mImageButtonScanQR;
    @BindView(R.id.layoutFTS)
    ConstraintLayout mLayoutFTS;
    @BindView(R.id.textViewCaptonProductList)
    TextView mTextViewCaptonProductList;
    @BindView(R.id.expandableIndicator)
    ImageView mExpandableIndicator;
    @BindView(R.id.recyclerViewProductList)
    RecyclerView mRecyclerViewProductList;
    @BindView(R.id.layoutProductList)
    ConstraintLayout mLayoutProductList;
    @BindView(R.id.imageViewLoadingProducts)
    ImageView mImageViewLoadingProducts;
    @BindView(R.id.textViewLoadingProducts)
    TextView mTextViewLoadingProducts;
    @BindView(R.id.layoutLoadingProducts)
    ConstraintLayout mLayoutLoadingProducts;
    @BindView(R.id.imageButtonInvertExRate)
    ImageButton mImageButtonInvertExRate;
    @BindView(R.id.layoutExchangeRate)
    RelativeLayout mLayoutExchangeRate;
    @BindView(R.id.fabBGLayout)
    View mFabBGLayout;
    @BindView(R.id.fabSelectAll)
    FloatingActionButton mFabSelectAll;
    @BindView(R.id.fabSelectAllLayout)
    LinearLayout mFabSelectAllLayout;
    @BindView(R.id.fabUnselectAll)
    FloatingActionButton mFabUnselectAll;
    @BindView(R.id.fabUnselectAllLayout)
    LinearLayout mFabUnselectAllLayout;
    @BindView(R.id.fabSetCategory)
    FloatingActionButton mFabSetCategory;
    @BindView(R.id.fabSetCategoryLayout)
    LinearLayout mFabSetCategoryLayout;
    @BindView(R.id.fabSetProject)
    FloatingActionButton mFabSetProject;
    @BindView(R.id.fabSetProjectLayout)
    LinearLayout mFabSetProjectLayout;
    @BindView(R.id.fabDeleteSelected)
    FloatingActionButton mFabDeleteSelected;
    @BindView(R.id.fabDeleteSelectedLayout)
    LinearLayout mFabDeleteSelectedLayout;
    @BindView(R.id.fabMenuButtonRoot)
    FloatingActionButton mFabMenuButtonRoot;
    @BindView(R.id.fabMenuButtonRootLayout)
    LinearLayout mFabMenuButtonRootLayout;
    @BindView(R.id.layoutPayeeOrDestAcc)
    LinearLayout mLayoutPayeeOrDestAcc;
    @BindView(R.id.layoutAmounts)
    LinearLayout mLayoutAmounts;
    @BindView(R.id.layoutRoot)
    LinearLayout mLayoutRoot;
    @BindView(R.id.layoutComment)
    TextInputLayout mLayoutComment;
    //</editor-fold>

    private MyPagerAdapter fragmentPagerAdapter;
    private OnDestAmountChangeListener onDestAmountChangeListener;
    private OnExRateTextChangedListener onExRateTextChangedListener;
    private String mPayeeName;
    private Transaction transaction;
    private Transaction srcTransaction;//исходная транзакция для сплита
    private Template template;
    private Sms sms;
    private int mLastTrType = Transaction.TRANSACTION_TYPE_EXPENSE;
    private Credit mCredit;
    private int credit_action = -1;
    private BigDecimal srcAmount;
    private double lat = 0;
    private double lon = 0;
    private int accuracy = 0;
    private String provider = "";
    private LocationManager locationManager;
    private boolean forceUpdateLocation = false;
    private boolean allowUpdateLocation;
    private boolean mIsBtnMorePressed = false;
    private boolean isExRateInverted = false;
    private boolean mDoNotChangeIsAmountEdited = false;
    private boolean isAmountEdited = false;
    private boolean isErrorLoadingProducts = false;
    private FabMenuController mFabMenuController;
    private List<TrEditItem> mTrEditItems;
    private LocationListener locationListener;
    private SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener;

    @Inject
    FtsHelper mFtsHelper;

    @Override
    protected int getLayoutResourceId() {
        return R.layout.activity_edit_transaction;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        FGApplication.getAppComponent().inject(this);

        if (!BuildConfig.DEBUG) {
            if (!Fabric.isInitialized()) {
                Fabric.with(this, new Crashlytics());
            }
        }

        ButterKnife.bind(this);

        mTrEditItems = PrefUtils.getTrEditorLayout(mPreferences, this);
        recreateViews();
        PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);

        //получаем объекты
        initObjects(savedInstanceState);

        amountEditor.setActivity(this);

        isAmountEdited = transaction.getAmount().compareTo(BigDecimal.ZERO) != 0;

        mRecyclerViewProductList.setLayoutManager(new LinearLayoutManager(this) {
            @Override
            public boolean canScrollVertically() {
                return false;
            }
        });

        locationListener = new LocationListener() {
            @Override
            public void onLocationChanged(android.location.Location location) {
                if (location == null)
                    return;
                lat = location.getLatitude();
                lon = location.getLongitude();
                accuracy = Math.round(location.getAccuracy());
                provider = location.getProvider();
                updateEdLocation();
            }

            @Override
            public void onStatusChanged(String provider, int status, Bundle extras) {

            }

            @Override
            public void onProviderEnabled(String provider) {

            }

            @Override
            public void onProviderDisabled(String provider) {

            }
        };

        sharedPreferenceChangeListener = (prefs, key) -> {
            if (key.equals(FgConst.PREF_TRANSACTION_EDITOR_CONSTRUCTOR)) {
                mTrEditItems = PrefUtils.getTrEditorLayout(mPreferences, ActivityEditTransaction.this);
                recreateViews();
            }
        };
    }

    @Override
    public void onDestroy() {
        PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
        super.onDestroy();
    }

    @Override
    public void onResume() {
        super.onResume();

        NotificationHelper.getInstance(this).cancel(SMSReceiver.NOTIFICATION_ID_TRANSACTION_AUTO_CREATED);
        NotificationCounter notificationCounter = new NotificationCounter(PreferenceManager.getDefaultSharedPreferences(this));
        notificationCounter.removeNotification(SMSReceiver.NOTIFICATION_ID_TRANSACTION_AUTO_CREATED);

        forceUpdateLocation = transaction.getID() < 0;
        allowUpdateLocation = mPreferences.getBoolean("detect_locations", false) & forceUpdateLocation & (srcTransaction == null);

        if (allowUpdateLocation) {
            ActivityEditTransactionPermissionsDispatcher.startDetectCoordsWithPermissionCheck(this);
        }

        if (transaction.getTransactionType() != Transaction.TRANSACTION_TYPE_TRANSFER) {
            mLastTrType = transaction.getTransactionType();
        }

        initUI();

        if (getIntent().getBooleanExtra("focus_to_category", false)) {
            Intent intent = new Intent(this, ActivityList.class);
            intent.putExtra("showHomeButton", false);
            intent.putExtra("model", new Category());
            intent.putExtra("requestCode", REQUEST_CODE_SELECT_MODEL);
            startActivityForResult(intent, REQUEST_CODE_SELECT_MODEL);
        }

        if (getIntent().getBooleanExtra("scan_qr", false)) {

            getIntent().removeExtra("scan_qr");
            Intent intent = new Intent(ActivityEditTransaction.this, ActivityScanQR.class);
            intent.putExtra("transaction", transaction);
            startActivityForResult(intent, RequestCodes.REQUEST_CODE_SCAN_QR);
        }
    }

    @Override
    protected void onPause() {
        removeUpdates();
        super.onPause();
    }

    private void recreateViews() {
        mLayoutRoot.removeView(teLayDateTime);
        mLayoutRoot.removeView(textInputLayoutAccount);
        mLayoutRoot.removeView(mLayoutPayeeOrDestAcc);
        mLayoutRoot.removeView(layoutCategory);
        mLayoutRoot.removeView(mLayoutAmounts);
        mLayoutRoot.removeView(layoutSms);
        mLayoutRoot.removeView(mLayoutFTS);
        mLayoutRoot.removeView(mLayoutProductList);
        mLayoutRoot.removeView(layoutProject);
        mLayoutRoot.removeView(layoutSimpleDebt);
        mLayoutRoot.removeView(layoutDepartment);
        mLayoutRoot.removeView(layoutLocation);
        mLayoutRoot.removeView(mLayoutComment);
        mLayoutRoot.removeView(mButtonMore);

        boolean focused = false;

        for (TrEditItem item : mTrEditItems) {
            switch (item.getID()) {
                case FgConst.TEI_DATETIME :
                    mLayoutRoot.addView(teLayDateTime);
                    break;
                case FgConst.TEI_ACCOUNT :
                    mLayoutRoot.addView(textInputLayoutAccount);
                    break;
                case FgConst.TEI_PAYEE_DEST_ACC :
                    mLayoutRoot.addView(mLayoutPayeeOrDestAcc);
                    if (!focused) {
                        mLayoutPayeeOrDestAcc.requestFocus();
                        focused = true;
                    }
                    break;
                case FgConst.TEI_CATEGORY :
                    mLayoutRoot.addView(layoutCategory);
                    break;
                case FgConst.TEI_AMOUNTS :
                    mLayoutRoot.addView(mLayoutAmounts);
                    if (!focused) {
                        amountEditor.requestFocus();
                        focused = true;
                    }
                    break;
                case FgConst.TEI_SMS :
                    mLayoutRoot.addView(layoutSms);
                    break;
                case FgConst.TEI_FTS :
                    mLayoutRoot.addView(mLayoutFTS);
                    break;
                case FgConst.TEI_PRODUCT_LIST :
                    mLayoutRoot.addView(mLayoutProductList);
                    break;
                case FgConst.TEI_PROJECT :
                    mLayoutRoot.addView(layoutProject);
                    break;
                case FgConst.TEI_SIMPLE_DEBT :
                    mLayoutRoot.addView(layoutSimpleDebt);
                    break;
                case FgConst.TEI_DEPARTMENT :
                    mLayoutRoot.addView(layoutDepartment);
                    break;
                case FgConst.TEI_LOCATION :
                    mLayoutRoot.addView(layoutLocation);
                    break;
                case FgConst.TEI_COMMENT :
                    mLayoutRoot.addView(mLayoutComment);
                    break;
            }
        }
        mLayoutRoot.addView(mButtonMore);
    }

    public void initUI() {
        if (getSupportActionBar() != null) {
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
            getSupportActionBar().setHomeAsUpIndicator(ContextCompat.getDrawable(this, R.drawable.ic_close_white));
        }

        initSrcAmount();

        initTemplateName();

        initDateTimeButtons();

        initAccount();

        initViewPager();

//        initViewPagerPayee();

        initCategory();

        initFTS();

        initProductList();

        initProject();

        initSimpleDebt();

        initDepartment();

        initLocation();

        initAmountEditor();

        initDestAmountEditor();

        initExRate();

        initComment();

        initSms();

        initFabMenu();

        updateControlsState();
    }

    public Transaction getTransaction() {
        return transaction;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        getMenuInflater().inflate(R.menu.menu_transaction_editor, menu);
        menu.findItem(R.id.action_go_home).setVisible(false);
        menu.findItem(R.id.action_show_help).setVisible(true);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_customize_layout:
                FragmentTrEditConstructorDialog dialog = new FragmentTrEditConstructorDialog();
                dialog.show(getSupportFragmentManager(),"fragment_tr_edit_constructor_dialog");
                return true;
            default:
                return false;
        }
    }

    @Override
    protected String getLayoutTitle() {
        if (transaction == null) {
            return "";
        }
        if (template == null) {
            if (transaction.getID() < 0) {
                switch (viewPager.getCurrentItem()) {
                    case 0:
                        return getResources().getString(R.string.act_create_transaction);
                    case 1:
                        return getResources().getString(R.string.ent_new_transfer);
                }
            } else {
                switch (viewPager.getCurrentItem()) {
                    case 0:
                        return getResources().getString(R.string.ent_edit_transaction);
                    case 1:
                        return getResources().getString(R.string.ent_edit_transfer);
                }
            }
        } else {
            if (template.getID() < 0) {
                return getResources().getString(R.string.act_create_template);
            } else {
                return getResources().getString(R.string.ent_edit_template);
            }

        }
        return "";
    }

    private boolean checkPayeeAndCreateIfNecessary(boolean updateAutocompleteAdapter) {
        if ((viewPager.getCurrentItem() == 0) && !mPayeeName.isEmpty()) {
            try {
                transaction.setPayeeID(PayeeManager.checkPayeeAndCreateIfNecessary(transaction.getPayeeID(), mPayeeName, this));
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (updateAutocompleteAdapter) {
                FragmentPayee fragmentPayee = getFragmentPayee();
                if (fragmentPayee != null) {
                    fragmentPayee.setAutocompleteAdapter();
                }
            }
        }

        return transaction.getPayeeID() >= 0;
    }

    private void updatePayeeWithDefCategory() {
        if (transaction.getPayeeID() < 0) return;
        Category category = TransactionManager.getCategory(transaction, this);
        Payee payee = TransactionManager.getPayee(transaction, this);
        Category defCategory = PayeeManager.getDefCategory(payee, this);
        if (defCategory.getID() != category.getID() & category.getID() >= 0) {
            PayeesDAO payeesDAO = PayeesDAO.getInstance(getApplicationContext());
            payee.setDefCategoryID(category.getID());
            try {
                payeesDAO.createModel(payee);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private void checkLocation() {
        if (transaction.getLocationID() < 0) {
            transaction.setLat(lat);
            transaction.setLon(lon);
            transaction.setAccuracy(accuracy);
        } else {
            transaction.setLat(0);
            transaction.setLon(0);
            transaction.setAccuracy(-1);
        }
    }

    private void deleteSrcSms() {
        if (sms != null) {
            SmsDAO smsDAO = SmsDAO.getInstance(getApplicationContext());
            smsDAO.deleteModel(sms, true, getApplicationContext());
            if (transaction.getComment().isEmpty()) {
                transaction.setComment(sms.getmBody());
            }
        }
    }

    public int validateTransaction() {
        Account src = TransactionManager.getSrcAccount(transaction, this);
        Account dst = TransactionManager.getDestAccount(transaction, this);
        if (transaction.getAccountID() < 0) {
            return ERR_EMPTY_SRC_ACCOUNT;
        } else if (dst.getID() >= 0 & src.getCabbageId() != dst.getCabbageId() & transaction.getExchangeRate().compareTo(BigDecimal.ZERO) == 0) {
            return ERR_EXRATE_ZERO;
        } else if (dst.getID() >= 0 & src.getCabbageId() != dst.getCabbageId() & transaction.getExchangeRate().compareTo(BigDecimal.ONE) == 0) {
            return ERR_EXRATE_ONE;
        } else {
            return 0;
        }
    }

    @OnClick(R.id.buttonSaveTransaction)
    public void onSaveClick() {

        switch (viewPager.getCurrentItem()) {
            case 0:
                if (transaction.getDestAccountID() > 0) {
                    transaction.setDestAccountID(-1);
                    initViewPagerPayee();
                    transaction.setExchangeRate(BigDecimal.ONE);
                    initExRate();
                }
                break;
            case 1:
                if (transaction.getPayeeID() >= 0) {
                    transaction.setPayeeID(-1);
                    initViewPagerPayee();
                }
                if (TransactionManager.getSrcAccount(transaction, this).getCabbageId() ==
                        TransactionManager.getDestAccount(transaction, this).getCabbageId()) {
                    transaction.setExchangeRate(BigDecimal.ONE);
                    initExRate();
                }
                break;
        }

        //region Данный блок работает только НЕ в режиме сплита
        if (srcTransaction == null) {
            //Если у транзакции нет получателя, но в поле ввода есть текст, значит создаем такого получателя
            checkPayeeAndCreateIfNecessary(false);

            //Устанавливаем текущему получателю в качестве категории по умолчанию текущую категорию
            updatePayeeWithDefCategory();
        }
        //endregion

        if (template == null) {
            switch (validateTransaction()) {
                case 0:
                    saveTransaction();
                    break;
                case ERR_EMPTY_SRC_ACCOUNT:
                    textInputLayoutAccount.setError(getString(R.string.err_specify_account));
                    break;
                case ERR_EXRATE_ZERO:
                    mTextInputLayoutExchangeRate.setError(getString(R.string.err_exrate_zero));
                    break;
                case ERR_EXRATE_ONE:
                    new AlertDialog.Builder(this)
                            .setNegativeButton(android.R.string.no, (dialog, which) -> {

                            })
                            .setPositiveButton(android.R.string.yes, (dialog, which) -> saveTransaction())
                            .setCancelable(false)
                            .setMessage(getString(R.string.err_exrate_one))
                            .show();
                    break;
                default:
                    Toast.makeText(ActivityEditTransaction.this, getResources().getString(R.string.msg_invalid_data_in_fields), Toast.LENGTH_SHORT).show();
            }
        } else {
            //Находимся в режиме редактирования шаблона
            template.extractFromTransaction(transaction);
            if (template.isValid()) {
                try {
                    TemplatesDAO.getInstance(getApplicationContext()).createModel(template);
                } catch (Exception e) {
                    Toast.makeText(this, R.string.msg_error_on_write_to_db, Toast.LENGTH_SHORT).show();
                    return;
                }
                finish();
            } else {
                Toast.makeText(ActivityEditTransaction.this, getResources().getString(R.string.msg_invalid_data_in_fields), Toast.LENGTH_SHORT).show();
            }
        }
    }

    private void saveTransaction() {
        PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).edit().putLong("last_account_id", transaction.getAccountID()).apply();

        //Если транзакция создается из смс, удаляем ее
        deleteSrcSms();

        //если явно не указано местоположение, пытаемся получить координаты. Если не удается явно задаем 0
        checkLocation();

        transaction.setAutoCreated(false);
        TransactionsDAO transactionsDAO = TransactionsDAO.getInstance(getApplicationContext());
        try {
            transaction = (Transaction) transactionsDAO.createModel(transaction);
        } catch (Exception e) {
            Toast.makeText(this, R.string.msg_error_on_write_to_db, Toast.LENGTH_SHORT).show();
            return;
        }

        if (srcTransaction != null) {
            editSrcTransaction();
            Intent result = new Intent();
            result.putExtra("src_transaction", transactionsDAO.getTransactionByID(srcTransaction.getID()));
            try {
                srcTransaction = (Transaction) transactionsDAO.createModel(srcTransaction);
            } catch (Exception e) {
                e.printStackTrace();
            }
            result.putExtra("split1", srcTransaction);
            result.putExtra("split2", transaction);
            setResult(RESULT_OK, result);
        } else {
            if (!(getIntent().getBooleanExtra("EXIT", false))) {
                setResult(RESULT_OK);
            }
        }

        if (mCredit != null) {
            SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
            switch (credit_action) {
                case Credit.DEBT_ACTION_BORROW:
                case Credit.DEBT_ACTION_TAKE:
                    preferences.edit().putLong("credit_dest_account", transaction.getDestAccountID()).apply();
                    break;
                case Credit.DEBT_ACTION_GRANT:
                case Credit.DEBT_ACTION_REPAY:
                    preferences.edit().putLong("credit_src_account", transaction.getAccountID()).apply();
                    break;
            }
            if (credit_action == Credit.DEBT_ACTION_REPAY | credit_action == Credit.DEBT_ACTION_TAKE) {
                showDebtPercentsDialog(mCredit, credit_action, transaction);
            } else {
                finish();
            }
        } else {
            BigDecimal balanceError = BigDecimal.ZERO;
            if (sms != null) {
                if (transactionsDAO.isTransactionLastForAccount(transaction)) {
                    Account account = AccountsDAO.getInstance(getApplicationContext()).getAccountByID(transaction.getAccountID());
                    balanceError = new SmsParser(sms, this).checkBalance(account);
                }
            }
            if (balanceError.compareTo(BigDecimal.ZERO) != 0) {
                showCorrectBalanceDialog(balanceError);
            } else {
                finish();
                if (getIntent().getBooleanExtra("EXIT", false)) {
                    this.finishAffinity();
                }
            }
        }
    }

    private void editSrcTransaction() {
        if (srcTransaction.getTransactionType() != Transaction.TRANSACTION_TYPE_TRANSFER) {
            int srcType;
            if (srcAmount.compareTo(BigDecimal.ZERO) >= 0) {
                srcType = Transaction.TRANSACTION_TYPE_INCOME;
            } else {
                srcType = Transaction.TRANSACTION_TYPE_EXPENSE;
            }
            srcTransaction.setAmount(srcAmount, srcType);
        } else {
            if (srcAmount.compareTo(BigDecimal.ZERO) <= 0) {
                srcTransaction.setAmount(srcAmount, srcTransaction.getTransactionType());
            } else {
                long acc1 = srcTransaction.getAccountID();
                long acc2 = srcTransaction.getDestAccountID();
                srcTransaction.setAccountID(acc2);
                srcTransaction.setDestAccountID(acc1);
                srcTransaction.setAmount(srcAmount, srcTransaction.getTransactionType());
            }
        }
    }

    @SuppressLint("StringFormatInvalid")
    private void showCorrectBalanceDialog(BigDecimal amount) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(R.string.ttl_confirm_action);
        Account account = TransactionManager.getSrcAccount(transaction, this);
        Cabbage cabbage = AccountManager.getCabbage(account, this);
        builder.setMessage(String.format(getString(R.string.msg_confirm_create_correcting_transaction), new CabbageFormatter(cabbage).format(amount)));

        // Set up the buttons
        builder.setPositiveButton("OK", new OnShowCorrectingDialogOkListener(amount, this));
        builder.setNegativeButton("Cancel", new OnShowCorrectingDialogCancelListener(this));

        builder.show();
    }

    @OnClick(R.id.buttonMore)
    public void onClick() {
        mIsBtnMorePressed = !mIsBtnMorePressed;
        updateControlsState();
    }

    private void showDebtPercentsDialog(Credit credit, int creditAction, Transaction transaction) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(R.string.ttl_confirm_action);
        builder.setMessage(getString(R.string.msg_confirmation_create_credit_percent_transaction));

        builder.setPositiveButton("OK", new OnShowDebtPercentDialogOkListener(credit, creditAction, transaction, this));
        builder.setNegativeButton("Cancel", new OnShowCorrectingDialogCancelListener(this));

        builder.show();
    }

    private void updateControlsState() {
        mButtonMore.setVisibility(mIsBtnMorePressed ? View.GONE : View.VISIBLE);

        class ItemVisibility {
            RelativeLayout layout;
            String id;
            private long entityId;

            private ItemVisibility(RelativeLayout layout, String id, long entityId) {
                this.layout = layout;
                this.id = id;
                this.entityId = entityId;
            }
        }

        List<ItemVisibility> views = Arrays.asList(
                new ItemVisibility(layoutCategory, FgConst.TEI_CATEGORY, transaction.getCategoryID()),
                new ItemVisibility(layoutProject, FgConst.TEI_PROJECT, transaction.getProjectID()),
                new ItemVisibility(layoutSimpleDebt, FgConst.TEI_SIMPLE_DEBT, transaction.getSimpleDebtID()),
                new ItemVisibility(layoutDepartment, FgConst.TEI_DEPARTMENT, transaction.getDepartmentID()),
                new ItemVisibility(layoutLocation, FgConst.TEI_LOCATION, transaction.getLocationID()));
        TrEditItem item;
        for (ItemVisibility itemVisibility : views) {
            item = PrefUtils.getTrEditItemByID(mTrEditItems, itemVisibility.id);
            if (item != null) {
                itemVisibility.layout.setVisibility((itemVisibility.entityId >= 0 | (!item.isHideUnderMore() || mIsBtnMorePressed))
                        & item.isVisible() ? View.VISIBLE : View.GONE);
            }
        }

        item = PrefUtils.getTrEditItemByID(mTrEditItems, FgConst.TEI_PRODUCT_LIST);
        if (item != null) {
            mLayoutProductList.setVisibility(
                    (isErrorLoadingProducts | transaction.getProductEntries().size() > 0
                    | (!item.isHideUnderMore() || mIsBtnMorePressed)
                    | getIntent().getBooleanExtra("load_products", false))
                     & item.isVisible() ? View.VISIBLE : View.GONE);
        }

        boolean scanQR = mPreferences.getBoolean(FgConst.PREF_ENABLE_SCAN_QR, true);

        item = PrefUtils.getTrEditItemByID(mTrEditItems, FgConst.TEI_FTS);
        if (item != null) {
            mLayoutFTS.setVisibility(
                    (transaction.getFN() > 0 | transaction.getFD() > 0 | transaction.getFP() > 0 | (!item.isHideUnderMore() || mIsBtnMorePressed)) & scanQR & item.isVisible() ? View.VISIBLE : View.GONE);
        }

        if (transaction.getTransactionType() == Transaction.TRANSACTION_TYPE_TRANSFER) {
            Account srcAccount = TransactionManager.getSrcAccount(transaction, this);
            Account dstAccount = TransactionManager.getDestAccount(transaction, this);

            if ((srcAccount.getCabbageId() != dstAccount.getCabbageId()) & (dstAccount.getID() >= 0)) {
                mLayoutExchangeRate.setVisibility(View.VISIBLE);
            } else {
                mLayoutExchangeRate.setVisibility(View.GONE);
            }
            Cabbage dstCabbage = AccountManager.getCabbage(dstAccount, this);
            destAmountEditor.setScale(dstCabbage.getDecimalCount());
            Cabbage srcCabbage = AccountManager.getCabbage(srcAccount, this);
            String s;
            if (onExRateTextChangedListener != null)
                edExchangeRate.removeTextChangedListener(onExRateTextChangedListener);
            isExRateInverted = mPreferences.getBoolean(String.format("%s/%s", srcCabbage.getCode(), dstCabbage.getCode()), false);
            if (!isExRateInverted) {
                s = String.format("%s/%s", srcCabbage.getCode(), dstCabbage.getCode());
                edExchangeRate.setText(String.valueOf(transaction.getExchangeRate().doubleValue()));
            } else {
                s = String.format("%s/%s", dstCabbage.getCode(), srcCabbage.getCode());
                edExchangeRate.setText(String.valueOf(BigDecimal.ONE.divide(transaction.getExchangeRate(), 5, RoundingMode.HALF_UP).doubleValue()));
            }
            if (onExRateTextChangedListener != null)
                edExchangeRate.addTextChangedListener(onExRateTextChangedListener);
            String hint = String.format("%s %s", getString(R.string.ent_exchange_rate), s);
            mTextInputLayoutExchangeRate.setHint(hint);
        } else {
            mLayoutExchangeRate.setVisibility(View.GONE);
        }
        destAmountEditor.setVisibility(mLayoutExchangeRate.getVisibility());

        amountEditor.setType(transaction.getTransactionType());

        destAmountEditor.setType(transaction.getTransactionType());

        updatePayeeHint();

        if (getSupportActionBar() != null) {
            getSupportActionBar().setTitle(getLayoutTitle());
        }

        boolean productsSelected = false;
        for (ProductEntry entry : transaction.getProductEntries()) {
            if (entry.isSelected()) {
                productsSelected = true;
                break;
            }
        }

        mFabMenuButtonRootLayout.setVisibility(productsSelected ? View.VISIBLE : View.GONE);
    }

    @SuppressWarnings("ConstantConditions")
    private void initSms() {
        if (sms != null) {
            SmsParser smsParser = new SmsParser(sms, getApplicationContext());
            Spannable text = new SpannableString(sms.getmBody());
            text.setSpan(new BackgroundColorSpan(ContextCompat.getColor(this, R.color.ColorAccount)), smsParser.mAccountBorders.first, smsParser.mAccountBorders.second, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            text.setSpan(new BackgroundColorSpan(ContextCompat.getColor(this, R.color.ColorAmount)), smsParser.mAmountBorders.first, smsParser.mAmountBorders.second, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            text.setSpan(new BackgroundColorSpan(ContextCompat.getColor(this, R.color.ColorAmount)), smsParser.mBalanceBorders.first, smsParser.mBalanceBorders.second, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            text.setSpan(new BackgroundColorSpan(ContextCompat.getColor(this, R.color.ColorPayee)), smsParser.mPayeeBorders.first, smsParser.mPayeeBorders.second, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            text.setSpan(new BackgroundColorSpan(ContextCompat.getColor(this, R.color.ColorDestAccount)), smsParser.mDestAccountBorders.first, smsParser.mDestAccountBorders.second, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            text.setSpan(new BackgroundColorSpan(ContextCompat.getColor(this, R.color.ColorType)), smsParser.mTrTypeBorders.first, smsParser.mTrTypeBorders.second, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            text.setSpan(new BackgroundColorSpan(ContextCompat.getColor(this, R.color.ColorCabbage)), smsParser.mCabbageAmountBorders.first, smsParser.mCabbageAmountBorders.second, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            text.setSpan(new BackgroundColorSpan(ContextCompat.getColor(this, R.color.ColorCabbage)), smsParser.mCabbageBalanceBorders.first, smsParser.mCabbageBalanceBorders.second, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            edSms.setText(text);

//            imageButtonAddMarker.setImageDrawable(IconGenerator.getInstance(this).getAddIcon(this));
            imageButtonAddMarker.setOnClickListener(v -> ActivityEditTransaction.this.showAddMarkerDialog());

            edSms.setCustomSelectionActionModeCallback(new ActionModeCallback(this));
        } else {
            layoutSms.setVisibility(View.GONE);
        }

    }

    private void showAddMarkerDialog() {
        int selStart = edSms.getSelectionStart();
        int selEnd = edSms.getSelectionEnd();

        if (selEnd == selStart) {
            Toast.makeText(ActivityEditTransaction.this, getString(R.string.msg_select_marker_text_before), Toast.LENGTH_SHORT).show();
            return;
        }

        AlertDialog.Builder builderSingle = new AlertDialog.Builder(this);
        builderSingle.setTitle(this.getResources().getString(R.string.msg_select_marker_type));

        final ArrayAdapter<SmsMarkerManager.SmsMarkerType> arrayAdapter = new ArrayAdapter<>(this,
                android.R.layout.select_dialog_singlechoice);
        arrayAdapter.addAll(SmsMarkerManager.getSmsMarkerTypeObjects(transaction.getTransactionType(), this));

        builderSingle.setNegativeButton(
                this.getResources().getString(android.R.string.cancel),
                (dialog, which) -> dialog.dismiss());


        String selectedText = sms.getmBody().subSequence(Math.max(0, Math.min(selStart, selEnd)),
                Math.max(0, Math.max(selStart, selEnd))).toString();
        builderSingle.setAdapter(arrayAdapter, new OnMarkersDialogOkListener(selectedText));
        builderSingle.show();
    }

    private void selectPayeeForMarker(final int markerType, final String selectedText) {
        if (!checkPayeeAndCreateIfNecessary(true)) {
            PayeeManager.ShowSelectPayeeDialog(ActivityEditTransaction.this, selectedPayee -> {
                transaction.setPayeeID(selectedPayee.getID());
                setPayeeName(selectedPayee.getName());
                ActivityEditTransaction.this.createSmsMarker(markerType, selectedText);
            });
        } else {
            ActivityEditTransaction.this.createSmsMarker(markerType, selectedText);
        }
    }

    private void createSmsMarker(final int markerType, final String selectedText) {
        SmsMarker smsMarker = null;

        switch (markerType) {
            case SmsParser.MARKER_TYPE_PAYEE: {
                if (transaction.getPayeeID() < 0) {
                    if (mPayeeName.isEmpty()) {
                        new AlertDialog.Builder(this)
                                .setNegativeButton(R.string.act_create, (dialog, which) -> {
                                    PayeesDAO payeesDAO = PayeesDAO.getInstance(ActivityEditTransaction.this);
                                    Payee payee = new Payee();
                                    payee.setName(selectedText);
                                    try {
                                        payee = (Payee) payeesDAO.createModel(payee);
                                        transaction.setPayeeID(payee.getID());
                                        setPayeeName(payee.getName());
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                    ActivityEditTransaction.this.createSmsMarker(markerType, selectedText);
                                })
                                .setPositiveButton(R.string.act_select, (dialog, which) -> selectPayeeForMarker(markerType, selectedText))
                                .setCancelable(false)
                                .setMessage(String.format(getString(R.string.ttl_create_new_payee_from_marker), selectedText))
                                .show();
                    } else {
                        selectPayeeForMarker(markerType, selectedText);
                    }
                    return;
                }
                if (transaction.getPayeeID() >= 0) {
                    smsMarker = new SmsMarker(-1, SmsParser.MARKER_TYPE_PAYEE, String.valueOf(transaction.getPayeeID()), selectedText);
                }
                break;
            }
            case SmsParser.MARKER_TYPE_DESTACCOUNT: {
                if (transaction.getDestAccountID() < 0) {
                    break;
                }
                smsMarker = new SmsMarker(-1, SmsParser.MARKER_TYPE_DESTACCOUNT, String.valueOf(transaction.getDestAccountID()), selectedText);
                break;
            }
            case SmsParser.MARKER_TYPE_IGNORE: {
                smsMarker = new SmsMarker(-1, SmsParser.MARKER_TYPE_IGNORE, "Ignore", selectedText);
                break;
            }
            case SmsParser.MARKER_TYPE_ACCOUNT: {
                if (transaction.getAccountID() < 0) {
                    break;
                }
                smsMarker = new SmsMarker(-1, SmsParser.MARKER_TYPE_ACCOUNT, String.valueOf(transaction.getAccountID()), selectedText);
                break;
            }
            case SmsParser.MARKER_TYPE_TRTYPE: {
                int type;
                if (viewPager.getCurrentItem() == 0) {
                    type = transaction.getAmountSign() ? 1 : -1;
                } else {
                    type = 0;
                }
                smsMarker = new SmsMarker(-1, SmsParser.MARKER_TYPE_TRTYPE, String.valueOf(type), selectedText);
                break;
            }
            case SmsParser.MARKER_TYPE_CABBAGE: {
                if (transaction.getAccountID() < 0) {
                    break;
                }
                Account account = TransactionManager.getSrcAccount(transaction, this);
                smsMarker = new SmsMarker(-1, SmsParser.MARKER_TYPE_CABBAGE,
                        String.valueOf(account.getCabbageId()),
                        selectedText);
                break;
            }
            default:
                break;
        }

        if (smsMarker != null) {//тру - создан новый паттерн

            //Пишем новый паттерн в БД
            SmsMarkersDAO smsMarkersDAO = SmsMarkersDAO.getInstance(getApplicationContext());
            try {
                smsMarkersDAO.createModel(smsMarker);
            } catch (Exception e) {
                Toast.makeText(this, R.string.msg_error_on_write_to_db, Toast.LENGTH_SHORT).show();
                return;
            }

            //если мы изменили паттерн валюты или знака, заново парсим смс и проверяем не нашли ли мы новую сумму.
            switch (markerType) {
                case SmsParser.MARKER_TYPE_CABBAGE:
                case SmsParser.MARKER_TYPE_TRTYPE: {
                    SmsParser smsParser1 = new SmsParser(sms, getApplicationContext());
                    int type = smsParser1.extractTrType();
                    transaction.setAmount(amountEditor.getAmount(), type);
                    if (transaction.getAmount().compareTo(BigDecimal.ZERO) == 0) {
                        Account account = TransactionManager.getSrcAccount(transaction, this);
                        BigDecimal extractedAmount = smsParser1.extractAmount(account);
                        transaction.setAmount(extractedAmount, type);
                        amountEditor.setAmount(transaction.getAmount());
                        amountEditor.setType(type);
                    }
                }
            }

            //заново оформляем TextView с смской
            initSms();
        }
    }

    private void initObjects(Bundle savedInstanceState) {
        if (savedInstanceState == null) {
            if (getIntent().getAction() != null) {
                switch (getIntent().getAction()) {
                    case FgConst.ACT_NEW_EXPENSE:
                        transaction = new Transaction(PrefUtils.getDefDepID(this));
                        transaction.setTransactionType(Transaction.TRANSACTION_TYPE_EXPENSE);
                        break;
                    case FgConst.ACT_NEW_INCOME:
                        transaction = new Transaction(PrefUtils.getDefDepID(this));
                        transaction.setTransactionType(Transaction.TRANSACTION_TYPE_INCOME);
                        break;
                    case FgConst.ACT_NEW_TRANSFER:
                        transaction = new Transaction(PrefUtils.getDefDepID(this));
                        transaction.setTransactionType(Transaction.TRANSACTION_TYPE_TRANSFER);
                        break;
                    default:
                        transaction = getIntent().getParcelableExtra("transaction");
                }
            } else {
                transaction = getIntent().getParcelableExtra("transaction");
            }
            if (transaction == null) {
                transaction = new Transaction(PrefUtils.getDefDepID(this));
            }
            if (getIntent().getBooleanExtra("update_date", false)) {
                transaction.setDateTime(new Date());
            }
            srcTransaction = getIntent().getParcelableExtra("src_transaction");
            if (srcTransaction != null) {
                srcAmount = new BigDecimal(srcTransaction.getAmount().doubleValue());
            } else {
                srcAmount = BigDecimal.ZERO;
            }
            template = getIntent().getParcelableExtra("template");
            mCredit = getIntent().getParcelableExtra("credit");
            credit_action = getIntent().getIntExtra("credit_action", -1);
            //получаем смс
            sms = getIntent().getParcelableExtra("sms");
            if (sms != null) {
                SmsParser smsParser = new SmsParser(sms, this);
                transaction = smsParser.extractTransaction();
            }

            if (getIntent().getStringExtra("template_name") != null) {
                if (!getIntent().getStringExtra("template_name").isEmpty()) {
                    try {
                        transaction = TransactionManager.templateToTransaction((Template) TemplatesDAO.getInstance(this).getModelByName(getIntent().getStringExtra("template_name")), this);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    getIntent().putExtra("transaction", transaction);
                }
            }
        } else {
            onRestoreInstanceState(savedInstanceState);
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("payee_name", mPayeeName);
        outState.putParcelable("transaction", transaction);
        outState.putParcelable("sms", sms);
        outState.putParcelable("src_transaction", srcTransaction);
        outState.putParcelable("template", template);
        outState.putParcelable("credit", mCredit);
        outState.putInt("credit_action", credit_action);
        outState.putInt("viewpager_current_item", viewPager.getCurrentItem());
        outState.putInt("last_transaction_type", mLastTrType);
        outState.putBoolean("is_button_more_pressed", mIsBtnMorePressed);
        outState.putBoolean("is_exrate_inverted", isExRateInverted);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        mPayeeName = savedInstanceState.getString("payee_name");
        transaction = savedInstanceState.getParcelable("transaction");
        sms = savedInstanceState.getParcelable("sms");
        srcTransaction = savedInstanceState.getParcelable("src_transaction");
        if (srcTransaction != null) {
            srcAmount = new BigDecimal(srcTransaction.getAmount().doubleValue());
        } else {
            srcAmount = BigDecimal.ZERO;
        }
        template = savedInstanceState.getParcelable("template");
        mCredit = savedInstanceState.getParcelable("credit");
        credit_action = savedInstanceState.getInt("credit_action");
        viewPager.setCurrentItem(savedInstanceState.getInt("viewpager_current_item"));
        mIsBtnMorePressed = savedInstanceState.getBoolean("is_button_more_pressed");
        isExRateInverted = savedInstanceState.getBoolean("is_exrate_inverted");
        mLastTrType = savedInstanceState.getInt("last_transaction_type");
    }

    //<editor-fold desc="Init fields" defaultstate="collapsed">
    private void initSrcAmount() {
        if (srcTransaction != null) {
            mTextInputLayoutSrcAmount.setVisibility(View.VISIBLE);
            Account account = TransactionManager.getSrcAccount(srcTransaction, this);
            Cabbage cabbage = AccountManager.getCabbage(account, this);
            CabbageFormatter cabbageFormatter = new CabbageFormatter(cabbage);
            textViewSrcAmount.setText(cabbageFormatter.format(srcAmount));
        }
    }

    private void initTemplateName() {
        if (template != null) {
            mTextInputLayoutTemplateName.setVisibility(View.VISIBLE);
            editTextTemplateName.setText(template.getName());
            editTextTemplateName.addTextChangedListener(new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {

                }

                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    template.setName(s.toString());
                }

                @Override
                public void afterTextChanged(Editable s) {

                }
            });
        }
    }

    private void initDateTimeButtons() {
        if (template != null || srcTransaction != null) {
            teLayDateTime.setVisibility(View.GONE);
        } else {
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.getInstance(this);
            edDate.setText(dateTimeFormatter.getDateMediumString(transaction.getDateTime()));
            edTime.setText(dateTimeFormatter.getTimeShortString(transaction.getDateTime()));
            new SwipeDetector(edDate).setOnSwipeListener(new SwipeDetector.onSwipeEvent() {
                @Override
                public void TapEventDetected(View v) {
                    onDateClick(edDate);
                }

                @Override
                public void SwipeEventDetected(View v, SwipeDetector.SwipeTypeEnum swipeType) {
                    switch (swipeType) {
                        case LEFT_TO_RIGHT:
                            transaction.setDateTime(new Date(transaction.getDateTime().getTime() - TimeUnit.DAYS.toMillis(1)));
                            break;
                        case RIGHT_TO_LEFT:
                            transaction.setDateTime(new Date(transaction.getDateTime().getTime() + TimeUnit.DAYS.toMillis(1)));
                            break;
                    }
                    initDateTimeButtons();
                }
            });
            new SwipeDetector(edTime).setOnSwipeListener(new SwipeDetector.onSwipeEvent() {
                @Override
                public void TapEventDetected(View v) {
                    onTimeClick(edTime);
                }

                @Override
                public void SwipeEventDetected(View v, SwipeDetector.SwipeTypeEnum swipeType) {
                    switch (swipeType) {
                        case LEFT_TO_RIGHT:
                            transaction.setDateTime(new Date(transaction.getDateTime().getTime() - TimeUnit.HOURS.toMillis(1)));
                            break;
                        case RIGHT_TO_LEFT:
                            transaction.setDateTime(new Date(transaction.getDateTime().getTime() + TimeUnit.HOURS.toMillis(1)));
                            break;
                    }
                    initDateTimeButtons();
                }
            });
        }
    }

    private void initAccount() {
        if (srcTransaction != null) {
            textViewAccount.setVisibility(View.GONE);
        } else {
            AccountsDAO accountsDAO = AccountsDAO.getInstance(getApplicationContext());

            SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);

            Account account = TransactionManager.getSrcAccount(transaction, this);
            if (preferences.getBoolean(FgConst.PREF_REMEMBER_LAST_ACCOUNT, true) && account.getID() < 0) {
                account = accountsDAO.getAccountByID(PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getLong("last_account_id", -1));
                transaction.setAccountID(account.getID());
            }
            Cabbage cabbage = AccountManager.getCabbage(account, this);
            if (account.getID() < 0) {
                textViewAccount.setText("");
            } else {
                textViewAccount.setText(String.format("%s (%s)", account.getName(), cabbage.getSimbol()));
            }
//            textViewAccountCabbage.setText(cabbage.getCode());

            amountEditor.setScale(cabbage.getDecimalCount());

            textViewAccount.setOnClickListener(view -> {
                Intent intent = new Intent(ActivityEditTransaction.this, ActivityAccounts.class);
                intent.putExtra("showHomeButton", false);
                intent.putExtra("model", new Account());
                intent.putExtra("destAccount", false);
                ActivityEditTransaction.this.startActivityForResult(intent, REQUEST_CODE_SELECT_MODEL);
            });
        }
    }

    private void setTransactionTypeControls(int transactionType) {
        switch (transactionType) {
            case Transaction.TRANSACTION_TYPE_TRANSFER:
                viewPager.setCurrentItem(1);
                break;
            case Transaction.TRANSACTION_TYPE_INCOME:
            case Transaction.TRANSACTION_TYPE_EXPENSE:
                viewPager.setCurrentItem(0);
                break;
        }
    }

    @Override
    public void destAccountTextViewClick() {
        Intent intent = new Intent(this, ActivityAccounts.class);
        intent.putExtra("showHomeButton", false);
        intent.putExtra("model", new Account());
        intent.putExtra("destAccount", true);
        startActivityForResult(intent, RequestCodes.REQUEST_CODE_SELECT_MODEL);
    }

    @Override
    public void InvertTransferDirectionClick() {
        long src = transaction.getAccountID();
        long dst = transaction.getDestAccountID();
        transaction.setAccountID(dst);
        transaction.setDestAccountID(src);
        initUI();
    }

    @Override
    public String getDestAccountName() {
        Account destAccount = TransactionManager.getDestAccount(transaction, this);
        String name = destAccount.getName();
        String code = AccountManager.getCabbage(destAccount, this).getSimbol();
        if (name.isEmpty()) {
            return "";
        } else {
            return String.format("%s (%s)", destAccount.getName(), code);
        }
    }

    // Extend from SmartFragmentStatePagerAdapter now instead for more dynamic ViewPager items
    private class MyPagerAdapter extends SmartFragmentStatePagerAdapter {

        MyPagerAdapter(FragmentManager fragmentManager) {
            super(fragmentManager);
        }

        // Returns total number of pages
        @Override
        public int getCount() {
            return 2;//FRAGMENTS_COUNT;
        }

        // Returns the fragment to display for that page
        @Override
        public Fragment getItem(int position) {
            switch (position) {
                case 0: // Fragment # 0 - This will show FirstFragment
                    if (mPayeeName != null && !mPayeeName.isEmpty()) {
                        setPayeeName(mPayeeName);
                    } else {
                        Payee payee = TransactionManager.getPayee(transaction, getApplicationContext());
                        setPayeeName(payee.getFullName());
                    }
                    FragmentPayee fragmentPayee = FragmentPayee.newInstance();
                    initViewPagerPayee();
                    return fragmentPayee;
                case 1:
                    return FragmentDestAccount.newInstance();
                default:
                    return null;
            }
        }

        // Returns the page title for the top indicator
        @Override
        public CharSequence getPageTitle(int position) {
            switch (position) {
                case FRAGMENT_PAYEE:
                    return getString(R.string.ent_payment);
                case FRAGMENT_DEST_ACCOUNT:
                    return getString(R.string.ent_transfer);
                default:
                    return null;
            }
        }

    }

    private void initViewPager() {
        if (srcTransaction != null) {
            tabLayoutType.setVisibility(View.GONE);
            viewPager.setVisibility(View.GONE);
        } else {
            fragmentPagerAdapter = new MyPagerAdapter(getSupportFragmentManager());
            viewPager.setAdapter(fragmentPagerAdapter);

            tabLayoutType.setVisibility(View.VISIBLE);
            viewPager.setVisibility(View.VISIBLE);

            tabLayoutType.setupWithViewPager(viewPager);
            tabLayoutType.setVisibility(mPreferences.getBoolean(FgConst.PREF_SHOW_TRANSACTION_TYPE_TITLES, true) ?
                    View.VISIBLE : View.GONE);
            setTransactionTypeControls(transaction.getTransactionType());
            viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                }

                @Override
                public void onPageSelected(int position) {
                    if (position == 0) {
                        transaction.setTransactionType(mLastTrType);
                    } else {
                        transaction.setTransactionType(Transaction.TRANSACTION_TYPE_TRANSFER);
                    }
                    updateControlsState();
                    setTransactionTypeControls(transaction.getTransactionType());
                }

                @Override
                public void onPageScrollStateChanged(int state) {
                }
            });
        }
    }

    @Nullable
    private FragmentPayee getFragmentPayee() {
        FragmentPayee fragmentPayee;
        try {
            fragmentPayee = (FragmentPayee) fragmentPagerAdapter.getRegisteredFragment(0);
        } catch (Exception e) {
            fragmentPayee = null;
        }
        return fragmentPayee;
    }

    private void initViewPagerPayee() {
         viewPager.setVisibility(srcTransaction == null ? View.VISIBLE : View.GONE);
    }

    @Override
    public String getPayeeName() {
        return mPayeeName;
    }

    @Override
    public String getPayeeHint() {
        String hint;
        switch (transaction.getTransactionType()) {
            default:
            case Transaction.TRANSACTION_TYPE_EXPENSE:
                hint = getString(R.string.ent_payee);
                break;
            case Transaction.TRANSACTION_TYPE_INCOME:
                hint = getString(R.string.ent_payer);
                break;
        }
        return hint;
    }

    @Override
    public void onPayeeTextViewClick() {
        Intent intent = new Intent(ActivityEditTransaction.this.getApplicationContext(), ActivityList.class);
        intent.putExtra("showHomeButton", false);
        intent.putExtra("model", PayeesDAO.getInstance(getApplicationContext()).getPayeeByID(transaction.getPayeeID()));
        intent.putExtra("requestCode", REQUEST_CODE_SELECT_MODEL);
        ActivityEditTransaction.this.startActivityForResult(intent, REQUEST_CODE_SELECT_MODEL);
    }

    @Override
    public void onPayeeItemClick(long payeeID) {
        Payee payee = PayeesDAO.getInstance(this).getPayeeByID(payeeID);
        transaction.setPayeeID(payee.getID());
        mPayeeName = payee.getFullName();
        Category defCategory = PayeeManager.getDefCategory(payee, ActivityEditTransaction.this);
        if (defCategory.getID() >= 0) {
            transaction.setCategoryID(defCategory.getID());
            ActivityEditTransaction.this.initCategory();
        }
        amountEditor.requestFocus();
    }

    @Override
    public void onPayeeTyping(String payeeName) {
        mPayeeName = payeeName;
    }

    @Override
    public void onClearPayee() {
        transaction.setPayeeID(-1);
        setPayeeName("");
    }

    @Override
    public int getPayeeSelectionStyle() {
        return Integer.valueOf(mPreferences.getString("payee_selection_style", "0"));
    }

    @Override
    public boolean isShowKeyboard() {
        return transaction.getID() < 0;
    }

    @Override
    public NestedItemFullNameAdapter getPayeeNameAutocompleteAdapter() {
        PayeesDAO payeesDAO = PayeesDAO.getInstance(this);
        List<IAbstractModel> payees;
        List<AutocompleteItem> autocompleteItems = new ArrayList<>();
        try {
            payees = (List<IAbstractModel>) payeesDAO.getAllModels();
        } catch (Exception e) {
            payees = new ArrayList<>();
        }

        BaseNode tree = TreeManager.convertListToTree(payees, IAbstractModel.MODEL_TYPE_PAYEE);
        for (BaseNode node : tree.getFlatChildrenList()) {
            autocompleteItems.add(new AutocompleteItem(node.getModel().getID(), node.getModel().getFullName()));
        }

        return new NestedItemFullNameAdapter(this, android.R.layout.simple_spinner_dropdown_item, autocompleteItems);
    }

    private void initCategory() {
        edCategory.setText(CategoriesDAO.getInstance(this).getCategoryByID(transaction.getCategoryID()).getFullName());
        edCategory.setOnClickListener(v -> {
            Intent intent = new Intent(ActivityEditTransaction.this.getApplicationContext(), ActivityList.class);
            intent.putExtra("showHomeButton", false);
            intent.putExtra("model", CategoriesDAO.getInstance(getApplicationContext()).getCategoryByID(transaction.getCategoryID()));
            intent.putExtra("requestCode", REQUEST_CODE_SELECT_MODEL);
            ActivityEditTransaction.this.startActivityForResult(intent, REQUEST_CODE_SELECT_MODEL);
        });
    }

    private void initFTS() {

        mTextViewFN.setText(String.valueOf(transaction.getFN()));
        mTextViewFD.setText(String.valueOf(transaction.getFD()));
        mTextViewFP.setText(String.valueOf(transaction.getFP()));

        mTextViewFN.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                try {
                    transaction.setFN(Long.valueOf(charSequence.toString()));
                } catch (NumberFormatException e) {
                    transaction.setFN(0);
                }
            }

            @Override
            public void afterTextChanged(Editable editable) {
            }
        });

        mTextViewFD.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                try {
                    transaction.setFD(Long.valueOf(charSequence.toString()));
                } catch (NumberFormatException e) {
                    transaction.setFD(0);
                }
            }

            @Override
            public void afterTextChanged(Editable editable) {
            }
        });

        mTextViewFP.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                try {
                    transaction.setFP(Long.valueOf(charSequence.toString()));
                } catch (NumberFormatException e) {
                    transaction.setFP(0);
                }
            }

            @Override
            public void afterTextChanged(Editable editable) {
            }
        });

        mImageButtonScanQR.setOnClickListener(view -> {
            Intent intent = new Intent(ActivityEditTransaction.this, ActivityScanQR.class);
            intent.putExtra("transaction", transaction);
            startActivityForResult(intent, RequestCodes.REQUEST_CODE_SCAN_QR);
        });

        mImageButtonDownloadReceipt.setOnClickListener(view -> {
            getIntent().putExtra("load_products", true);
            initProductList();
        });
    }

    AdapterProducts mAdapterProducts;
    boolean mProductListExpanded = true;

    private void loadProducts() {
        if (mFtsHelper.isFtsCredentialsAvailiable(this)) {
            final RotateAnimation spinAnim = new RotateAnimation(360, 0f,
                    Animation.RELATIVE_TO_SELF, 0.5f,
                    Animation.RELATIVE_TO_SELF, 0.5f);

            spinAnim.setInterpolator(new LinearInterpolator());
            spinAnim.setDuration(2000);
            spinAnim.setRepeatCount(Animation.INFINITE);
            mLayoutLoadingProducts.setVisibility(View.VISIBLE);
            mImageViewLoadingProducts.setVisibility(View.VISIBLE);
            mImageViewLoadingProducts.startAnimation(spinAnim);
            mTextViewLoadingProducts.setText(getString(R.string.ttl_loading_products));
            updateControlsState();
            IDownloadProductsListener downloadProductsListener = new IDownloadProductsListener() {
                @Override
                public void onDownload(List<ProductEntry> productEntries, String payeeName) {
                    spinAnim.cancel();
                    spinAnim.reset();
                    mLayoutLoadingProducts.setVisibility(View.GONE);
                    transaction.getProductEntries().clear();
                    transaction.getProductEntries().addAll(productEntries);
                    getIntent().removeExtra("load_products");
                    fillProductList();
                    if ((viewPager.getCurrentItem() == 0) && mPayeeName != null && mPayeeName.isEmpty()) {
                        setPayeeName(payeeName);
                    }
                    isErrorLoadingProducts = false;
                }

                @Override
                public void onAccepted() {
                    initProductList();
                }

                @Override
                public void onFailure(String errorMessage, boolean tryAgain) {
                    isErrorLoadingProducts = true;
                    getIntent().removeExtra("load_products");
                    spinAnim.cancel();
                    spinAnim.reset();
                    mImageViewLoadingProducts.setVisibility(View.GONE);
                    mTextViewLoadingProducts.setText(errorMessage);
                    updateControlsState();
                }
            };
            unsubscribeOnDestroy(mFtsHelper.downloadProductEntryList(transaction, downloadProductsListener));
        } else {
            mLayoutLoadingProducts.setVisibility(View.GONE);
            fillProductList();
            if (!mPreferences.getBoolean(FgConst.PREF_FTS_DO_NOT_SHOW_AGAIN, false)) {
                startActivityForResult(
                        new Intent(ActivityEditTransaction.this, ActivityFtsLogin.class),
                        RequestCodes.REQUEST_CODE_ENTER_FTS_LOGIN);
            }
        }
    }

    private void initProductList() {
        if (getIntent().getBooleanExtra("load_products", false)) {
            loadProducts();
        } else {
            fillProductList();
        }

        mRecyclerViewProductList.setVisibility(mProductListExpanded ? View.VISIBLE : View.GONE);

        mExpandableIndicator.setImageDrawable(mProductListExpanded ? getDrawable(R.drawable.ic_expand_more) : getDrawable(R.drawable.ic_expand_less));

        mExpandableIndicator.setOnClickListener(view -> {
            mProductListExpanded = !mProductListExpanded;
            initProductList();
        });

    }

    private void fillProductList() {
        isErrorLoadingProducts = false;
        mLayoutLoadingProducts.setVisibility(View.GONE);
        mAdapterProducts = new AdapterProducts(transaction, this, new AdapterProducts.IProductChangedListener() {
            @Override
            public void onProductChanged(int position, ProductEntry productEntry) {
                List<ProductEntry> entries = transaction.getProductEntries();
                if (position < entries.size()) {
                    entries.set(position, productEntry);
                } else {
                    entries.add(productEntry);
                }
                mAdapterProducts.notifyDataSetChanged();

                if (!isAmountEdited) {
                    BigDecimal sum = BigDecimal.ZERO;
                    for (ProductEntry entry : transaction.getProductEntries()) {
                        sum = sum.add(entry.getPrice().multiply(entry.getQuantity()));
                    }
                    transaction.setAmount(sum, sum.compareTo(BigDecimal.ZERO) <= 0 ?
                            Transaction.TRANSACTION_TYPE_EXPENSE : Transaction.TRANSACTION_TYPE_INCOME);
                    mDoNotChangeIsAmountEdited = true;
                    initAmountEditor();
                    mDoNotChangeIsAmountEdited = false;
                }
            }

            @Override
            public void onProductDeleted(int position) {
                transaction.getProductEntries().remove(position);
                mAdapterProducts.notifyDataSetChanged();
            }

            @Override
            public void onResidueMoved() {
                initAmountEditor();
                mAdapterProducts.notifyDataSetChanged();
            }

            @Override
            public void onProductSelected() {
                updateControlsState();
            }
        });
        mAdapterProducts.setHasStableIds(true);
        mRecyclerViewProductList.setAdapter(mAdapterProducts);
        mAdapterProducts.notifyDataSetChanged();
        updateControlsState();
    }

    private void initProject() {
        edProject.setText(ProjectsDAO.getInstance(this).getProjectByID(transaction.getProjectID()).getFullName());
        edProject.setOnClickListener(v -> {
            Intent intent = new Intent(ActivityEditTransaction.this.getApplicationContext(), ActivityList.class);
            intent.putExtra("showHomeButton", false);
            intent.putExtra("model", ProjectsDAO.getInstance(getApplicationContext()).getProjectByID(transaction.getProjectID()));
            intent.putExtra("requestCode", REQUEST_CODE_SELECT_MODEL);
            ActivityEditTransaction.this.startActivityForResult(intent, REQUEST_CODE_SELECT_MODEL);
        });
    }

    private void initSimpleDebt() {
        mTextViewSimpleDebt.setText("");
        mTextViewSimpleDebt.setText(TransactionManager.getSimpleDebt(transaction, this).getName());
        mTextViewSimpleDebt.setOnClickListener(v -> {
            Intent intent = new Intent(ActivityEditTransaction.this.getApplicationContext(), ActivityModelList.class);
            intent.putExtra("showHomeButton", false);
            intent.putExtra("model", SimpleDebtsDAO.getInstance(getApplicationContext()).getSimpleDebtByID(transaction.getSimpleDebtID()));
            intent.putExtra("cabbageID", AccountsDAO.getInstance(getApplicationContext()).getAccountByID(transaction.getAccountID()).getCabbageId());
            intent.putExtra("requestCode", REQUEST_CODE_SELECT_MODEL);
            ActivityEditTransaction.this.startActivityForResult(intent, REQUEST_CODE_SELECT_MODEL);
        });
    }

    private void initDepartment() {
        edDepartment.setText(DepartmentsDAO.getInstance(this).getDepartmentByID(transaction.getDepartmentID()).getFullName());
        edDepartment.setOnClickListener(v -> {
            Intent intent = new Intent(ActivityEditTransaction.this.getApplicationContext(), ActivityList.class);
            intent.putExtra("showHomeButton", false);
            intent.putExtra("model", DepartmentsDAO.getInstance(getApplicationContext()).getDepartmentByID(transaction.getDepartmentID()));
            intent.putExtra("requestCode", REQUEST_CODE_SELECT_MODEL);
            ActivityEditTransaction.this.startActivityForResult(intent, REQUEST_CODE_SELECT_MODEL);
        });
    }

    private void initAmountEditor() {
        amountEditor.setAmount(transaction.getAmount());
        amountEditor.setType(transaction.getTransactionType());
        amountEditor.setHint(getResources().getString(R.string.ent_amount));
        amountEditor.mOnAmountChangeListener = (newAmount, newType) -> {
            if (!mDoNotChangeIsAmountEdited) {
                isAmountEdited = true;
            }
            transaction.setAmount(newAmount, newType);
            destAmountEditor.setAmount(TransferManager.getDestAmount(transaction));
            if (newType != Transaction.TRANSACTION_TYPE_TRANSFER) {
                mLastTrType = newType;
            }
            if (srcTransaction != null) {
                srcAmount = srcTransaction.getAmount().subtract(transaction.getAmount());
                ActivityEditTransaction.this.initSrcAmount();
            }
            ActivityEditTransaction.this.updatePayeeHint();
            if (transaction.getProductEntries().size() > 0) {
//                    initProductList();
                mAdapterProducts.notifyDataSetChanged();
            }
        };

        if (getIntent().getBooleanExtra("focus_to_amount", false)) {
            amountEditor.setFocus();
        }
    }

    private void initDestAmountEditor() {
        destAmountEditor.setActivity(this);
        destAmountEditor.setAmount(transaction.getAmount().multiply(transaction.getExchangeRate()));
        destAmountEditor.setType(transaction.getTransactionType());
        destAmountEditor.setHint(getResources().getString(R.string.ent_dest_amount));
        onDestAmountChangeListener = new OnDestAmountChangeListener();
        destAmountEditor.mOnAmountChangeListener = onDestAmountChangeListener;
    }

    private void initExRate() {
        mImageButtonInvertExRate.setOnClickListener(view -> {
            isExRateInverted = !isExRateInverted;

            mPreferences.edit().putBoolean(String.format("%s/%s",
                    TransactionManager.getSrcCabbage(transaction, ActivityEditTransaction.this).getCode(),
                    TransactionManager.getDstCabbage(transaction, ActivityEditTransaction.this).getCode()),
                    isExRateInverted).apply();
            updateControlsState();
        });
        edExchangeRate.setText(String.valueOf(transaction.getExchangeRate().doubleValue()));
        if (onExRateTextChangedListener == null) {
            onExRateTextChangedListener = new OnExRateTextChangedListener();
            edExchangeRate.addTextChangedListener(onExRateTextChangedListener);
        }
    }

    private void initComment() {
        edComment.setText(transaction.getComment());
        edComment.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                transaction.setComment(s.toString());
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });
    }

    private void initLocation() {
        if (srcTransaction != null) {
            layoutLocation.setVisibility(View.GONE);
        } else {
            edLocation.setText("");
//            imageButtonDeleteLocation.setImageDrawable(IconGenerator.getInstance(this).getDeleteIcon(this));

            if (transaction.getLocationID() >= 0) {
                edLocation.setText(LocationsDAO.getInstance(this).getLocationByID(transaction.getLocationID()).getFullName());
            } else {
                if (transaction.getLat() != 0 & transaction.getLon() != 0) {
                    String latSymbol = transaction.getLat() > 0 ? "N" : "S";
                    String lonSymbol = transaction.getLon() > 0 ? "E" : "W";
                    DecimalFormat df = new DecimalFormat("0.00000");
                    edLocation.setText(String.format("%s %s %s %s ±%sm",
                            latSymbol, df.format(transaction.getLat()), lonSymbol, df.format(transaction.getLon()), String.valueOf(transaction.getAccuracy())));
                }
            }

            edLocation.setOnClickListener(v -> {
                Intent intent = new Intent(ActivityEditTransaction.this.getApplicationContext(), ActivityList.class);
                intent.putExtra("showHomeButton", false);
                intent.putExtra("model", LocationsDAO.getInstance(getApplicationContext()).getLocationByID(transaction.getLocationID()));
                intent.putExtra("requestCode", REQUEST_CODE_SELECT_MODEL);
                ActivityEditTransaction.this.startActivityForResult(intent, REQUEST_CODE_SELECT_MODEL);
            });

            if (allowUpdateLocation) {
                ActivityEditTransactionPermissionsDispatcher.startDetectCoordsWithPermissionCheck(this);
            }
        }
    }
    //</editor-fold>

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        // NOTE: delegate the permission handling to generated method
        ActivityEditTransactionPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults);
    }

    @OnClick({R.id.imageButtonDeleteLocation, R.id.imageButtonDeleteCategory, R.id.imageButtonDeleteDebt,
            R.id.imageButtonDeleteProject, R.id.imageButtonDeleteDepartment})
    void onTrashButtonClick(View v) {
        switch (v.getId()) {
            case R.id.imageButtonDeleteLocation:
                transaction.setLocationID(-1);
                transaction.setLat(0);
                transaction.setLon(0);
                allowUpdateLocation = false;
                initLocation();
                break;
            case R.id.imageButtonDeleteProject:
                transaction.setProjectID(-1);
                initProductList();
                initProject();
                break;
            case R.id.imageButtonDeleteDebt:
                transaction.setSimpleDebtID(-1);
                initSimpleDebt();
                break;
            case R.id.imageButtonDeleteDepartment:
                transaction.setDepartmentID(-1);
                initDepartment();
                break;
            case R.id.imageButtonDeleteCategory:
                transaction.setCategoryID(-1);
                initProductList();
                initCategory();
                break;
        }
    }

    private void updateEdLocation() {
        if (transaction.getLocationID() < 0 & forceUpdateLocation) {
            String latSymbol = lat > 0 ? "N" : "S";
            String lonSymbol = lon > 0 ? "E" : "W";
            DecimalFormat df = new DecimalFormat("0.00000");
            edLocation.setText(String.format("%s\n%s %s %s %s\n±%sm %s",
                    getString(R.string.ent_current_location), latSymbol, df.format(lat), lonSymbol, df.format(lon),
                    String.valueOf(accuracy), provider));
        } else {
            Location location = TransactionManager.getLocation(transaction, this);
            if (location.getID() > 0) {
                edLocation.setText(location.getName());
            }
        }
    }

    private void removeUpdates() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED ||
                ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            if (locationManager != null) {
                locationManager.removeUpdates(locationListener);
            }
        }
    }

    //<editor-fold desc="Permission dispatcher" defaultstate="collapsed">
    @NeedsPermission({Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION})
    void startDetectCoords() {
        if (transaction.getLocationID() < 0 & allowUpdateLocation) {
            locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

            if (locationManager != null && locationManager.getAllProviders().contains(LocationManager.NETWORK_PROVIDER))
                if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                    locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
                }

            if (locationManager != null && locationManager.getAllProviders().contains(LocationManager.GPS_PROVIDER))
                if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
                }
        }
    }

    @OnShowRationale({Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION})
    void showRationaleForContact(PermissionRequest request) {
        // NOTE: Show a rationale to explain why the permission is needed, e.g. with a dialog.
        // Call proceed() or cancel() on the provided PermissionRequest to continue or abort
        showRationaleDialog(R.string.msg_permission_location_rationale, request);
    }

    @OnPermissionDenied({Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION})
    void onLocationDenied() {
        // NOTE: Deal with a denied permission, e.g. by showing specific UI
        // or disabling certain functionality
        Toast.makeText(this, R.string.msg_permission_location_denied, Toast.LENGTH_SHORT).show();
    }

    @OnNeverAskAgain({Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION})
    void onLocationNeverAskAgain() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                & ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            mPreferences.edit().putBoolean("detect_locations", false).apply();
        } else {
            allowUpdateLocation = true;
        }
        if (!allowUpdateLocation) {
            Toast.makeText(this, R.string.msg_permission_location_never_askagain, Toast.LENGTH_SHORT).show();
        }
    }

    private void showRationaleDialog(@StringRes int messageResId, final PermissionRequest request) {
        new AlertDialog.Builder(this)
                .setPositiveButton(R.string.act_next, (dialog, which) -> request.proceed())
                .setNegativeButton(android.R.string.cancel, (dialog, which) -> request.cancel())
                .setCancelable(false)
                .setMessage(messageResId)
                .show();
    }
    //</editor-fold>

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        getIntent().removeExtra("focus_to_category");
        if (resultCode == RESULT_OK && requestCode == REQUEST_CODE_SELECT_MODEL && data != null) {
            IAbstractModel model = data.getParcelableExtra("model");
            switch (model.getModelType()) {
                case IAbstractModel.MODEL_TYPE_ACCOUNT:
                    Account account = (Account) model;
                    if (!data.getBooleanExtra("destAccount", false)) {
                        transaction.setAccountID(account.getID());
                        viewPager.requestFocus();
                        Cabbage cabbage = AccountManager.getCabbage(account, ActivityEditTransaction.this);
                        textViewAccount.setText(String.format("%s (%s)", account.getName(), cabbage.getSimbol()));
                        amountEditor.setScale(cabbage.getDecimalCount());
                    } else {
                        transaction.setDestAccountID(account.getID());
                        transaction.setPayeeID(-1);
                        findViewById(R.id.edittext_amount).requestFocus();
                    }
                    break;
                case IAbstractModel.MODEL_TYPE_CATEGORY:
                    transaction.setCategoryID(model.getID());
                    initCategory();
                    amountEditor.setFocus();
                    break;
                case IAbstractModel.MODEL_TYPE_PAYEE:
                    Payee payee = (Payee) model;
                    transaction.setPayeeID(payee.getID());
                    mPayeeName = payee.getFullName();
                    if (transaction.getPayeeID() >= 0) {
                        Category defCategory = PayeeManager.getDefCategory(payee, ActivityEditTransaction.this);
                        if (defCategory.getID() >= 0) {
                            transaction.setCategoryID(defCategory.getID());
                            ActivityEditTransaction.this.initCategory();
                        }
                        amountEditor.requestFocus();
                    }
                    break;
                case IAbstractModel.MODEL_TYPE_PROJECT:
                    transaction.setProjectID(model.getID());
                    initProject();
                    break;
                case IAbstractModel.MODEL_TYPE_SIMPLEDEBT:
                    transaction.setSimpleDebtID(model.getID());
                    initSimpleDebt();
                    break;
                case IAbstractModel.MODEL_TYPE_DEPARTMENT:
                    transaction.setDepartmentID(model.getID());
                    initDepartment();
                    break;
                case IAbstractModel.MODEL_TYPE_LOCATION:
                    transaction.setLocationID(model.getID());
                    forceUpdateLocation = transaction.getLocationID() < 0;
                    allowUpdateLocation = true;
                    initLocation();
                    break;
            }
        } else if (resultCode == RESULT_OK && requestCode == REQUEST_CODE_SELECT_MODEL_FOR_PRODUCT && data != null) {
            IAbstractModel model = data.getParcelableExtra("model");
            switch (model.getModelType()) {
                case IAbstractModel.MODEL_TYPE_CATEGORY:
                    for (ProductEntry entry : transaction.getProductEntries()) {
                        if (entry.isSelected()) {
                            entry.setCategoryID(model.getID());
                        }
                    }
                    break;
                case IAbstractModel.MODEL_TYPE_PROJECT:
                    for (ProductEntry entry : transaction.getProductEntries()) {
                        if (entry.isSelected()) {
                            entry.setProjectID(model.getID());
                        }
                    }
                    break;
            }
            for (ProductEntry entry : transaction.getProductEntries()) {
                entry.setSelected(false);
            }
            mAdapterProducts.notifyDataSetChanged();
            mFabMenuController.forceCloseFABMenu();
            updateControlsState();
        } else if (resultCode == RESULT_OK && requestCode == RequestCodes.REQUEST_CODE_SCAN_QR) {
            transaction = data.getParcelableExtra("transaction");
            getIntent().putExtra("load_products", true);
            initUI();
        } else if (requestCode == RequestCodes.REQUEST_CODE_ENTER_FTS_LOGIN) {
            if (resultCode != RESULT_OK) {
                getIntent().removeExtra("load_products");
            }
        } else {
            switch (requestCode) {
                case IAbstractModel.MODEL_TYPE_LOCATION:
                    initLocation();
                    break;
            }
        }
//        setFieldsVisibility();
    }

    //<editor-fold desc="Date & Time pickers" defaultstate="collapsed">
//    @OnClick(R.id.editTextDate)
    public void onDateClick(View view) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(transaction.getDateTime());
        new DatePickerDialog(this, (datePicker, year, monthOfYear, dayOfMonth) -> {
            Calendar calendar1 = Calendar.getInstance();
            calendar1.setTime(transaction.getDateTime());
            calendar1.set(year, monthOfYear, dayOfMonth);
            transaction.setDateTime(calendar1.getTime());
            initDateTimeButtons();
        }, calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH))
                .show();
    }

    public void onTimeClick(View view) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(transaction.getDateTime());
        new TimePickerDialog(this,
                (timePicker, hourOfDay, minute) -> {
                    Calendar calendar1 = Calendar.getInstance();
                    calendar1.setTime(transaction.getDateTime());
                    calendar1.set(calendar1.get(Calendar.YEAR), calendar1.get(Calendar.MONTH), calendar1.get(Calendar.DAY_OF_MONTH), hourOfDay, minute);
                    transaction.setDateTime(calendar1.getTime());
                    initDateTimeButtons();
                },
                calendar.get(Calendar.HOUR_OF_DAY),
                calendar.get(Calendar.MINUTE),
                DateTimeFormatter.is24(this)
        ).show();
    }
    //</editor-fold>

    @Override
    public boolean showHelp() {
        super.showHelp();

        MaterialShowcaseView.resetSingleUse(this, SHOWCASE_ID);

        ShowcaseConfig config = new ShowcaseConfig();
        config.setDelay(500); // half second between each showcase view

        MaterialShowcaseSequence sequence = new MaterialShowcaseSequence(this, SHOWCASE_ID);

        sequence.setConfig(config);

        String gotIt = getResources().getString(R.string.act_next);
        //+Вводный экран
        //+дата/время Нажмите, чтобы изменить дату или время транзакции
        //Счет Выберите из списка счет
        //Получатель/счет назначения
        //Категория
        //Сумма
        //Сумма в валюте назначения
        //Курс
        //Комментарий

        sequence.addSequenceItem(new MaterialShowcaseView.Builder(this)
                .setTarget(new View(this)).setDismissText(gotIt)
                .setContentText(getString(R.string.hlp_tr_editor_intro))
                .setMaskColour(ContextCompat.getColor(this, R.color.ColorPrimaryTransparent))
                .build());

        sequence.addSequenceItem(new MaterialShowcaseView.Builder(this)
                .setTarget(edDate).setDismissText(gotIt).withRectangleShape()
                .setMaskColour(ContextCompat.getColor(this, R.color.ColorPrimaryTransparent))
                .setContentText(R.string.hlp_tr_editor_date)
                .build());

        sequence.addSequenceItem(new MaterialShowcaseView.Builder(this)
                .setTarget(edTime).setDismissText(gotIt).withRectangleShape()
                .setMaskColour(ContextCompat.getColor(this, R.color.ColorPrimaryTransparent))
                .setContentText(R.string.hlp_tr_editor_time)
                .build());

        String accountHint = "";
        switch (transaction.getTransactionType()) {
            case Transaction.TRANSACTION_TYPE_INCOME:
                accountHint = getString(R.string.hlp_tr_editor_account_income);
                break;
            case Transaction.TRANSACTION_TYPE_EXPENSE:
            case Transaction.TRANSACTION_TYPE_TRANSFER:
                accountHint = getString(R.string.hlp_tr_editor_account_outcome_or_transfer);
                break;
        }
        sequence.addSequenceItem(new MaterialShowcaseView.Builder(this)
                .setTarget(textViewAccount).setDismissText(gotIt).withRectangleShape()
                .setMaskColour(ContextCompat.getColor(this, R.color.ColorPrimaryTransparent))
                .setContentText(accountHint)
                .build());

        String payeeHint = "";
        switch (transaction.getTransactionType()) {
            case Transaction.TRANSACTION_TYPE_INCOME:
                payeeHint = getString(R.string.hlp_tr_editor_payee_income);
                break;
            case Transaction.TRANSACTION_TYPE_EXPENSE:
                payeeHint = getString(R.string.hlp_tr_editor_payee_outcome);
                break;
            case Transaction.TRANSACTION_TYPE_TRANSFER:
                payeeHint = getString(R.string.hlp_tr_editor_dest_account);
                break;
        }
        sequence.addSequenceItem(new MaterialShowcaseView.Builder(this)
                .setTarget(viewPager).setDismissText(gotIt).withRectangleShape()
                .setMaskColour(ContextCompat.getColor(this, R.color.ColorPrimaryTransparent))
                .setContentText(payeeHint)
                .build());

        sequence.addSequenceItem(new MaterialShowcaseView.Builder(this)
                .setTarget(edCategory).setDismissText(gotIt).withRectangleShape()
                .setMaskColour(ContextCompat.getColor(this, R.color.ColorPrimaryTransparent))
                .setContentText(getString(R.string.hlp_tr_editor_category))
                .build());

        sequence.addSequenceItem(new MaterialShowcaseView.Builder(this)
                .setTarget(amountEditor).setDismissText(gotIt).withRectangleShape()
                .setMaskColour(ContextCompat.getColor(this, R.color.ColorPrimaryTransparent))
                .setContentText(getString(R.string.hlp_tr_editor_amount))
                .build());

        switch (transaction.getTransactionType()) {
            case Transaction.TRANSACTION_TYPE_INCOME:
            case Transaction.TRANSACTION_TYPE_EXPENSE:
                sequence.addSequenceItem(new MaterialShowcaseView.Builder(this)
                        .setTarget(amountEditor.btnAmountSign).setDismissText(gotIt).withRectangleShape()
                        .setMaskColour(ContextCompat.getColor(this, R.color.ColorPrimaryTransparent))
                        .setContentText(getString(R.string.hlp_tr_editor_amount_sign))
                        .build());
                break;
        }

        //Если мы в режиме перевода между счетами с разными валютами, показываем хинт для суммы в валюте
        //счета назначения и курса
        if (destAmountEditor.getVisibility() == View.VISIBLE) {
            sequence.addSequenceItem(new MaterialShowcaseView.Builder(this)
                    .setTarget(destAmountEditor).setDismissText(gotIt).withRectangleShape()
                    .setMaskColour(ContextCompat.getColor(this, R.color.ColorPrimaryTransparent))
                    .setContentText(getString(R.string.hlp_tr_editor_amount_dest_account))
                    .build());

            sequence.addSequenceItem(new MaterialShowcaseView.Builder(this)
                    .setTarget(edExchangeRate).setDismissText(gotIt).withRectangleShape()
                    .setMaskColour(ContextCompat.getColor(this, R.color.ColorPrimaryTransparent))
                    .setContentText(getString(R.string.hlp_tr_editor_exchange_rate))
                    .build());
        }

        sequence.start();

        return true;
    }

    private void updatePayeeHint() {
        FragmentPayee fragmentPayee = getFragmentPayee();
        if (fragmentPayee != null) {
            fragmentPayee.setHint(getPayeeHint());
        }
    }

    private void setPayeeName(String payeeName) {
        mPayeeName = payeeName;
        if (getFragmentPayee() != null) {
            getFragmentPayee().setPayeeName(payeeName);
        }
    }

    private class OnShowCorrectingDialogCancelListener implements DialogInterface.OnClickListener {
        final Activity mActivity;

        OnShowCorrectingDialogCancelListener(Activity mActivity) {
            this.mActivity = mActivity;
        }

        @Override
        public void onClick(DialogInterface dialog, int which) {
            dialog.cancel();
            mActivity.finish();
        }
    }

    private class OnShowCorrectingDialogOkListener implements DialogInterface.OnClickListener {
        final BigDecimal mAmount;
        final Activity mActivity;

        OnShowCorrectingDialogOkListener(BigDecimal mAmount, Activity mActivity) {
            this.mAmount = mAmount;
            this.mActivity = mActivity;
        }

        @Override
        public void onClick(DialogInterface dialog, int which) {
            Transaction cortr = new Transaction(PrefUtils.getDefDepID(ActivityEditTransaction.this));
            cortr.setAmount(mAmount, mAmount.compareTo(BigDecimal.ZERO));
            cortr.setAccountID(transaction.getAccountID());
            Intent intent = new Intent(mActivity, ActivityEditTransaction.class);
            intent.putExtra("transaction", cortr);
            startActivityForResult(intent, RequestCodes.REQUEST_CODE_EDIT_TRANSACTION);
            mActivity.finish();
        }
    }

    private class OnShowDebtPercentDialogOkListener implements DialogInterface.OnClickListener {
        final Credit mCredit;
        final int mDebtAction;
        final Activity mActivity;
        final Transaction mTransaction;

        OnShowDebtPercentDialogOkListener(Credit credit, int debtAction, Transaction transaction, Activity activity) {
            mCredit = credit;
            mDebtAction = debtAction;
            mActivity = activity;
            mTransaction = transaction;
        }

        @Override
        public void onClick(DialogInterface dialog, int which) {
            Transaction percents = new Transaction(PrefUtils.getDefDepID(ActivityEditTransaction.this));
            percents.setDateTime(new Date(mTransaction.getDateTime().getTime() + 1));

            switch (mDebtAction) {
                case Credit.DEBT_ACTION_REPAY:
                    percents.setPayeeID(mCredit.getPayeeID());
                    percents.setCategoryID(mCredit.getCategoryID());
                    percents.setTransactionType(Transaction.TRANSACTION_TYPE_EXPENSE);
                    break;
                case Credit.DEBT_ACTION_TAKE:
                    percents.setPayeeID(mCredit.getPayeeID());
                    percents.setCategoryID(mCredit.getCategoryID());
                    percents.setTransactionType(Transaction.TRANSACTION_TYPE_INCOME);
                    break;
            }

            Intent intent = new Intent(mActivity, ActivityEditTransaction.class);
            intent.putExtra("transaction", percents);
            startActivityForResult(intent, RequestCodes.REQUEST_CODE_EDIT_TRANSACTION);
            mActivity.finish();
        }
    }

    private class OnDestAmountChangeListener implements AmountEditor.OnAmountChangeListener {
        @Override
        public void OnAmountChange(BigDecimal newAmount, int newType) {
            transaction.setExchangeRate(TransferManager.getExRate(transaction, newAmount));
            edExchangeRate.removeTextChangedListener(onExRateTextChangedListener);
            BigDecimal visibleExRate;
            if (!isExRateInverted) {
                visibleExRate = transaction.getExchangeRate();
            } else {
                visibleExRate = BigDecimal.ONE.divide(transaction.getExchangeRate(), 5, RoundingMode.HALF_UP);
            }
            edExchangeRate.setText(String.valueOf(visibleExRate.doubleValue()));
            edExchangeRate.addTextChangedListener(onExRateTextChangedListener);
        }
    }

    private class OnExRateTextChangedListener implements TextWatcher {

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            try {
                BigDecimal rate;
                DecimalFormatSymbols symbols = new DecimalFormatSymbols();
//                symbols.setGroupingSeparator(',');
                symbols.setDecimalSeparator('.');
                DecimalFormat df = new DecimalFormat();
                df.setDecimalFormatSymbols(symbols);
                df.setParseBigDecimal(true);
                try {
                    rate = (BigDecimal) df.parse(s.toString());
                } catch (ParseException e) {
                    rate = BigDecimal.ONE;
                }
                if (isExRateInverted) {
                    if (rate.compareTo(BigDecimal.ZERO) != 0) {
                        rate = BigDecimal.ONE.divide((rate), 5, RoundingMode.HALF_UP);
                    } else {
                        rate = BigDecimal.ONE;
                    }
                }
                transaction.setExchangeRate(rate);
                destAmountEditor.mOnAmountChangeListener = null;
                destAmountEditor.setAmount(TransferManager.getDestAmount(transaction));
                destAmountEditor.mOnAmountChangeListener = onDestAmountChangeListener;
            } catch (NumberFormatException nfe) {
                //Todo уведомлять пользователя о том, что число некорректно
            }
        }

        @Override
        public void afterTextChanged(Editable s) {
        }
    }

    private void initFabMenu() {
        mFabMenuController = new FabMenuController(mFabMenuButtonRoot, mFabBGLayout, this,
                mFabSetCategoryLayout, mFabSetProjectLayout, mFabDeleteSelectedLayout, mFabUnselectAllLayout, mFabSelectAllLayout);
        FabMenuSelectionItemClickListener clickListener = new FabMenuSelectionItemClickListener();
        mFabDeleteSelected.setOnClickListener(clickListener);
        mFabUnselectAll.setOnClickListener(clickListener);
        mFabSelectAll.setOnClickListener(clickListener);
        mFabSetCategory.setOnClickListener(clickListener);
        mFabSetProject.setOnClickListener(clickListener);

    }

    private class FabMenuSelectionItemClickListener implements View.OnClickListener {
        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.fabSelectAll: {
                    for (ProductEntry entry : transaction.getProductEntries()) {
                        entry.setSelected(true);
                    }
                    mAdapterProducts.notifyDataSetChanged();
                    mFabMenuController.closeFABMenu();
                    updateControlsState();
                    break;
                }
                case R.id.fabUnselectAll: {
                    for (ProductEntry entry : transaction.getProductEntries()) {
                        entry.setSelected(false);
                    }
                    mAdapterProducts.notifyDataSetChanged();
                    mFabMenuController.closeFABMenu();
                    updateControlsState();
                    break;
                }
                case R.id.fabSetCategory: {
                    Intent intent = new Intent(ActivityEditTransaction.this.getApplicationContext(), ActivityList.class);
                    intent.putExtra("showHomeButton", false);
                    intent.putExtra("model", CategoriesDAO.getInstance(getApplicationContext()).getCategoryByID(transaction.getCategoryID()));
                    intent.putExtra("requestCode", REQUEST_CODE_SELECT_MODEL_FOR_PRODUCT);
                    ActivityEditTransaction.this.startActivityForResult(intent, REQUEST_CODE_SELECT_MODEL_FOR_PRODUCT);
                    break;
                }
                case R.id.fabSetProject: {
                    Intent intent = new Intent(ActivityEditTransaction.this.getApplicationContext(), ActivityList.class);
                    intent.putExtra("showHomeButton", false);
                    intent.putExtra("model", ProjectsDAO.getInstance(getApplicationContext()).getProjectByID(transaction.getProjectID()));
                    intent.putExtra("requestCode", REQUEST_CODE_SELECT_MODEL_FOR_PRODUCT);
                    ActivityEditTransaction.this.startActivityForResult(intent, REQUEST_CODE_SELECT_MODEL_FOR_PRODUCT);
                    break;
                }
                case R.id.fabDeleteSelected: {
                    for (int i = transaction.getProductEntries().size() - 1; i >= 0; i--) {
                        if (transaction.getProductEntries().get(i).isSelected()) {
                            transaction.getProductEntries().remove(i);
                        }
                    }
                    mAdapterProducts.notifyDataSetChanged();
                    mFabMenuController.closeFABMenu();
                    updateControlsState();
                    break;
                }
            }
        }
    }

    private class ActionModeCallback implements ActionMode.Callback {
        private static final int MENU_ID_SET_MARKER = 0;
        final Activity mActivity;

        ActionModeCallback(Activity mActivity) {
            this.mActivity = mActivity;
        }

        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            menu.add(0, MENU_ID_SET_MARKER, MENU_ID_SET_MARKER, R.string.act_set_marker).setShowAsAction(MenuItem.SHOW_AS_ACTION_WITH_TEXT | MenuItem.SHOW_AS_ACTION_ALWAYS);
            return true;
        }

        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            return true;
        }

        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            switch (item.getItemId()) {
                case MENU_ID_SET_MARKER: {
                    showAddMarkerDialog();
                }
            }
            return true;
        }

        @Override
        public void onDestroyActionMode(ActionMode mode) {

        }
    }

    private class OnMarkersDialogOkListener implements DialogInterface.OnClickListener {
        private final String selectedText;

        OnMarkersDialogOkListener(String selectedText) {
            this.selectedText = selectedText;
        }

        @Override
        public void onClick(DialogInterface dialog, int which) {
            if (sms == null) {
                return;
            }

            ListView lw = ((AlertDialog) dialog).getListView();
            SmsMarkerManager.SmsMarkerType checkedItem = (SmsMarkerManager.SmsMarkerType) lw.getAdapter().getItem(which);

            createSmsMarker(checkedItem.id, selectedText);
        }
    }
}