public final class NotificationController {

    private static class NotificationControllerHolder {
        private static final NotificationController INSTANCE = new NotificationController();
    }

    private boolean needShowNotification = true;

    public static NotificationController getInstance() {
        return NotificationControllerHolder.INSTANCE;
    }

    public void setNeedShowNotification(final boolean needShowNotification) {
        this.needShowNotification = needShowNotification;
    }

    public void showNotification(@NonNull final Context context,
                                 @NonNull final String notificationTitle,
                                 @NonNull final String notificationText) {
        OPFLog.logMethod(context, notificationTitle, notificationText);

        final NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context)
                .setDefaults(Notification.DEFAULT_SOUND);

        if (needShowNotification) {
            final Intent intent = new Intent(context, MainActivity.class);
            intent.setAction(MainActivity.OPEN_MESSAGES_FRAGMENT_ACTION);
            final PendingIntent pendingIntent = PendingIntent.getActivity(
                    context,
                    0,
                    intent,
                    0
            );

            notificationBuilder.setSmallIcon(R.drawable.notification_icon)
                    .setContentTitle(notificationTitle)
                    .setContentText(notificationText)
                    .setAutoCancel(true)
                    .setContentIntent(pendingIntent);
        }

        ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE))
                .notify(0, notificationBuilder.build());
    }
} public final class StateController {

    private static final String STATE_PREFS_NAME = "org.onepf.pushchat.STATE_PREFS_NAME";

    private static final String IS_REGID_SAVED_KEY = "IS_REGID_SAVED_KEY";

    private static final String IS_NO_AVAILABLE_PROVIDER_KEY = "IS_NO_AVAILABLE_PROVIDER_KEY";

    private StateController() {
        throw new UnsupportedOperationException();
    }

    @NonNull
    public static PushState getState(@NonNull final Context context) {
        final OPFPushHelper helper = OPFPush.getHelper();
        if (isNoAvailableProvider(context)) {
            return PushState.NO_AVAILABLE_PROVIDER;
        } else if (helper.isRegistered()) {
            if (isRegIdSavedOnServer(context)) {
                //helper is registered and reg id is saved on server;
                return PushState.REGISTERED;
            } else {
                //helper is registered but reg id is no saved on server;
                return PushState.REGISTERING;
            }
        } else if (helper.isRegistering()) {
            return PushState.REGISTERING;
        } else {
            if (isRegIdSavedOnServer(context)) {
                //helper is unregistered but reg id is no removed on server;
                return PushState.UNREGISTERING;
            } else {
                //helper is unregistered and reg id is removed on server;
                return PushState.UNREGISTERED;
            }
        }
    }

    public static void putRegIdSavedOnServerValue(@NonNull final Context context,
                                                  final boolean isSaved) {
        context.getSharedPreferences(STATE_PREFS_NAME, MODE_PRIVATE)
                .edit()
                .putBoolean(IS_REGID_SAVED_KEY, isSaved)
                .apply();
    }

    public static void putNoAvailableProviderValue(@NonNull final Context context,
                                                   final boolean isNoAvailableProvider) {
        context.getSharedPreferences(STATE_PREFS_NAME, MODE_PRIVATE)
                .edit()
                .putBoolean(IS_NO_AVAILABLE_PROVIDER_KEY, isNoAvailableProvider)
                .apply();
    }

    public static boolean isRegIdSavedOnServer(@NonNull final Context context) {
        final SharedPreferences sharedPreferences = context
                .getSharedPreferences(STATE_PREFS_NAME, MODE_PRIVATE);
        return sharedPreferences.getBoolean(IS_REGID_SAVED_KEY, false);
    }

    private static boolean isNoAvailableProvider(@NonNull final Context context) {
        final SharedPreferences sharedPreferences = context
                .getSharedPreferences(STATE_PREFS_NAME, MODE_PRIVATE);
        return sharedPreferences.getBoolean(IS_NO_AVAILABLE_PROVIDER_KEY, false);
    }
} public static class MessagesContract {
    public static final String TABLE_NAME = "messages";

    public static final Uri TABLE_URI = CONTENT_BASE_URI.buildUpon().appendPath(TABLE_NAME).build();
    public static final int ALL_URI_CODE = 0;
    public static final int URI_CODE = 1;

    public static class MessageEntry {
        public static final String ID = BaseColumns._ID;
        public static final String SENDER_UUID = "sender_uuid";
        public static final String SENDER_NAME = "sender_name";
        public static final String MESSAGE = "message";
        public static final String RECEIVED_TIME = "received_time";
    }
} @SuppressWarnings("PMD.NonThreadSafeSingleton")
public final class DatabaseHelper extends SQLiteOpenHelper {

    private static final String DATABASE_NAME = "org.onepf.pushchat.db";
    private static final int DATABASE_VERSION = 1;

    private static final String COMMA_SEP = ",";

    private static final String SQL_CREATE_CONTACTS_TABLE =
            "CREATE TABLE " + ContactsContract.TABLE_NAME + " ( "
                    + ContactEntry.ID + " INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL" + COMMA_SEP
                    + ContactEntry.NAME + " TEXT" + COMMA_SEP
                    + ContactEntry.UUID + " TEXT UNIQUE NOT NULL"
                    + " )";

    private static final String SQL_CREATE_MESSAGES_TABLE =
            "CREATE TABLE " + MessagesContract.TABLE_NAME + " ( "
                    + MessageEntry.ID + " INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL" + COMMA_SEP
                    + MessageEntry.SENDER_UUID + " TEXT NOT NULL" + COMMA_SEP
                    + MessageEntry.SENDER_NAME + " TEXT" + COMMA_SEP
                    + MessageEntry.MESSAGE + " TEXT NOT NULL" + COMMA_SEP
                    + MessageEntry.RECEIVED_TIME + " LONG"
                    + " )";

    private static final String SQL_DELETE_CONTACTS_TABLE = "DROP TABLE IF EXISTS "
            + ContactsContract.TABLE_NAME;

    private static final String SQL_DELETE_MESSAGES_TABLE = "DROP TABLE IF EXISTS "
            + MessagesContract.TABLE_NAME;

    private static final int MESSAGE_OPERATION_TOKEN = 1;
    private static final int CONTACT_OPERATION_TOKEN = 2;
    private static final int QUERY_UUIDS_TOKEN = 3;
    private static final int QUERY_CONTACT_NAME_TOKEN = 4;

    @NonNull
    private final Context appContext;

    @NonNull
    private final AsyncQueryHandler asyncQueryHandler;

    private static volatile DatabaseHelper instance;

    private DatabaseHelper(@NonNull final Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        this.appContext = context.getApplicationContext();
        this.asyncQueryHandler = new CommonAsyncQueryHandler(context.getContentResolver());
    }

    public static DatabaseHelper getInstance(@NonNull final Context context) {
        if (instance == null) {
            synchronized (DatabaseHelper.class) {
                if (instance == null) {
                    instance = new DatabaseHelper(context);
                }
            }
        }

        return instance;
    }

    @Override
    public void onCreate(@NonNull final SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL(SQL_CREATE_CONTACTS_TABLE);
        sqLiteDatabase.execSQL(SQL_CREATE_MESSAGES_TABLE);
    }

    @Override
    public void onUpgrade(@NonNull final SQLiteDatabase sqLiteDatabase,
                          final int oldVersion,
                          final int newVersion) {
        if (oldVersion < newVersion) {
            sqLiteDatabase.execSQL(SQL_DELETE_MESSAGES_TABLE);
            sqLiteDatabase.execSQL(SQL_DELETE_CONTACTS_TABLE);
            onCreate(sqLiteDatabase);
        }
    }

    public void addMessage(@NonNull final Message message) {
        new QueryContactNameQueryHandler(appContext.getContentResolver(), queryContactNameCallback(message))
                .startQuery(
                        QUERY_CONTACT_NAME_TOKEN,
                        null,
                        ContactsContract.TABLE_URI,
                        new String[]{ContactEntry.NAME},
                        ContactEntry.UUID + "=?",
                        new String[]{message.getSenderUuid()},
                        null
                );
    }

    private QueryContactNameQueryHandler.QueryContactNameCallback queryContactNameCallback(
            @NonNull final Message message
    ) {
        return new QueryContactNameQueryHandler.QueryContactNameCallback() {
            @Override
            public void onComplete(@NonNull final String name) {
                final ContentValues contentValues = new ContentValues();
                contentValues.put(MessageEntry.SENDER_UUID, message.getSenderUuid());
                contentValues.put(MessageEntry.SENDER_NAME, name);
                contentValues.put(MessageEntry.MESSAGE, message.getMessageText());
                contentValues.put(MessageEntry.RECEIVED_TIME, message.getReceivedTime());

                asyncQueryHandler.startInsert(MESSAGE_OPERATION_TOKEN, null, MessagesContract.TABLE_URI, contentValues);
            }
        };
    }

    public void deleteMessages() {
        asyncQueryHandler.startDelete(MESSAGE_OPERATION_TOKEN, null, MessagesContract.TABLE_URI, null, null);
    }

    public void addContact(@NonNull final Contact contact) {
        final String contactName = contact.getName();
        final String contactUuid = contact.getUuid();

        final ContentValues contactContentValues = new ContentValues();
        contactContentValues.put(ContactEntry.NAME, contactName);
        contactContentValues.put(ContactEntry.UUID, contactUuid);

        asyncQueryHandler.startInsert(CONTACT_OPERATION_TOKEN, null, ContactsContract.TABLE_URI, contactContentValues);

        final ContentValues messageContentValues = new ContentValues();
        messageContentValues.put(MessageEntry.SENDER_NAME, contactName);
        asyncQueryHandler.startUpdate(
                MESSAGE_OPERATION_TOKEN,
                null,
                MessagesContract.TABLE_URI,
                messageContentValues,
                MessageEntry.SENDER_UUID + "=?",
                new String[]{contactUuid}
        );
    }

    public void deleteContact(final long id) {
        asyncQueryHandler.startDelete(
                CONTACT_OPERATION_TOKEN,
                null,
                ContactsContract.TABLE_URI,
                ContactEntry.ID + "=?",
                new String[]{String.valueOf(id)}
        );
    }

    public void queryAllContactsUuids(@NonNull final QueryContactsUuidsCallback callback) {
        new ContactsUuidsAsyncQueryHandler(appContext.getContentResolver(), callback).startQuery(
                QUERY_UUIDS_TOKEN,
                null,
                ContactsContract.TABLE_URI,
                new String[]{ContactEntry.UUID},
                null,
                null,
                null
        );
    }

    public boolean isUuidAdded(@NonNull final String uuid) {
        final Cursor cursor = getReadableDatabase().query(
                ContactsContract.TABLE_NAME,
                new String[]{ContactEntry.UUID},
                ContactEntry.UUID + "=?",
                new String[]{uuid},
                null,
                null,
                null
        );

        final boolean isUuidAdded = cursor.getCount() > 0;
        cursor.close();
        return isUuidAdded;
    }

    public boolean isContactsTableEmpty() {
        final Cursor cursor = getReadableDatabase().query(
                ContactsContract.TABLE_NAME,
                new String[]{ContactEntry.ID},
                null,
                null,
                null,
                null,
                null
        );

        final boolean isEmpty = cursor.getCount() == 0;
        cursor.close();
        return isEmpty;
    }

    @NonNull
    public String querySenderUuidById(final long id) {
        final Cursor cursor = getReadableDatabase().query(
                MessagesContract.TABLE_NAME,
                new String[]{MessageEntry.SENDER_UUID},
                MessageEntry.ID + "=?",
                new String[]{String.valueOf(id)},
                null,
                null,
                null
        );

        String senderUuid = "";
        if (cursor.getCount() != 0) {
            cursor.moveToFirst();
            senderUuid = cursor.getString(cursor.getColumnIndexOrThrow(MessageEntry.SENDER_UUID));
        }
        cursor.close();
        return senderUuid;
    }

    public static class ContactsUuidsAsyncQueryHandler extends AsyncQueryHandler {

        @NonNull
        private final QueryContactsUuidsCallback callback;

        public ContactsUuidsAsyncQueryHandler(@NonNull final ContentResolver contentResolver,
                                              @NonNull final QueryContactsUuidsCallback callback) {
            super(contentResolver);
            this.callback = callback;
        }

        @Override
        protected void onQueryComplete(final int token, final Object cookie, final Cursor cursor) {
            final Set<String> uuids = new HashSet<>();
            if (token == QUERY_UUIDS_TOKEN) {
                cursor.moveToFirst();
                while (true) {
                    uuids.add(cursor.getString(cursor.getColumnIndexOrThrow(ContactEntry.UUID)));
                    if (cursor.isLast()) {
                        break;
                    }
                    cursor.moveToNext();
                }
            }
            cursor.close();
            callback.onComplete(uuids);
        }

        public interface QueryContactsUuidsCallback {

            void onComplete(@NonNull final Set<String> uuids);
        }
    }

    private static class CommonAsyncQueryHandler extends AsyncQueryHandler {

        public CommonAsyncQueryHandler(@NonNull final ContentResolver contentResolver) {
            super(contentResolver);
        }
    }

    private static class QueryContactNameQueryHandler extends AsyncQueryHandler {

        @NonNull
        private final QueryContactNameCallback callback;

        public QueryContactNameQueryHandler(@NonNull final ContentResolver contentResolver,
                                            @NonNull final QueryContactNameCallback callback) {
            super(contentResolver);
            this.callback = callback;
        }

        @Override
        protected void onQueryComplete(final int token, final Object cookie, final Cursor cursor) {
            if (token == QUERY_CONTACT_NAME_TOKEN) {
                if (cursor.getCount() > 0) {
                    cursor.moveToFirst();
                    callback.onComplete(cursor.getString(cursor.getColumnIndexOrThrow(ContactEntry.NAME)));
                } else {
                    callback.onComplete("");
                }
            }
            cursor.close();
        }

        private interface QueryContactNameCallback {

            void onComplete(@NonNull final String name);
        }
    }
} public enum PushState {

    REGISTERED,

    REGISTERING,

    UNREGISTERED,

    UNREGISTERING,

    NO_AVAILABLE_PROVIDER
} public final class Message {

    @NonNull
    private final String senderUuid;

    @NonNull
    private final String messageText;

    private final long receivedTime;

    public Message(@NonNull final String senderUuid,
                   @NonNull final String messageText,
                   final long receivedTime) {
        this.senderUuid = senderUuid;
        this.messageText = messageText;
        this.receivedTime = receivedTime;
    }

    @NonNull
    public String getSenderUuid() {
        return senderUuid;
    }

    @NonNull
    public String getMessageText() {
        return messageText;
    }

    public long getReceivedTime() {
        return receivedTime;
    }
} public final class FailedPushResult extends PushResult {

    @NonNull
    public final String errorMessage;

    public FailedPushResult(@NonNull final PushReceiver pushReceiver,
                            @NonNull final String errorMessage) {
        super(pushReceiver);
        this.errorMessage = errorMessage;
    }
} public final class PushMessageResponse {

    @Nullable
    public final PushResult[] successed;

    @Nullable
    public final FailedPushResult[] failed;

    @NonNull
    public final String message;

    public PushMessageResponse(@Nullable final PushResult[] successed,
                               @Nullable final FailedPushResult[] failed,
                               @NonNull final String message) {
        this.successed = successed;
        this.failed = failed;
        this.message = message;
    }
} public final class NetworkController {

    private final PushService pushService;

    @SuppressWarnings("PMD.AccessorClassGeneration")
    private static final class NetworkControllerHolder {
        private static final NetworkController INSTANCE = new NetworkController();
    }

    private NetworkController() {
        final RestAdapter restAdapter = new RestAdapter.Builder()
                .setEndpoint("https://onepf-opfpush.appspot.com/_ah/api/opfpush/v1")
                .setConverter(new GsonConverter(new GsonBuilder().create()))
                .build();
        pushService = restAdapter.create(PushService.class);
    }

    public static NetworkController getInstance() {
        return NetworkControllerHolder.INSTANCE;
    }

    public void register(@NonNull final Context context,
                         @NonNull final String providerName,
                         @NonNull final String registrationId) {

        final RegistrationRequestBody body =
                new RegistrationRequestBody(getUuid(context), providerName, registrationId);

        pushService.register(body, registrationCallback(context, providerName, registrationId));
    }

    public void unregister(@NonNull final Context context) {
        final UnregistrationRequestBody body = new UnregistrationRequestBody(getUuid(context));
        pushService.unregister(body, unregistrationCallback(context));
    }

    public void pushMessage(@NonNull final Context context,
                            @NonNull final String message,
                            @NonNull final Callback<PushMessageResponse> pushMessageCallback) {
        DatabaseHelper.getInstance(context).queryAllContactsUuids(
                new QueryContactsUuidsCallback() {
                    @Override
                    public void onComplete(@NonNull final Set<String> uuids) {
                        final PushMessageRequestBody body = new PushMessageRequestBody(
                                uuids,
                                getUuid(context),
                                message
                        );
                        pushService.push(body, pushMessageCallback);
                    }
                });
    }

    public void exist(@NonNull final String uuid,
                      @NonNull final Callback<ExistResponse> callback) {
        pushService.exist(uuid, callback);
    }

    public void getTopics(@NonNull final Context context,
                          @NonNull final Callback<TopicsResponse> callback) {
        pushService.getTopics(getUuid(context), callback);
    }

    public void subscribe(@NonNull final Context context,
                          @NonNull final String topic,
                          @NonNull final Callback<Object> callback) {
        pushService.subscribe(new SubscribeOrUnsubscribeRequestBody(topic, getUuid(context)), callback);
    }

    public void unsubscribe(@NonNull final Context context,
                            @NonNull final String topic,
                            @NonNull final Callback<Object> callback) {
        pushService.unsubscribe(new SubscribeOrUnsubscribeRequestBody(topic, getUuid(context)), callback);
    }

    private String getUuid(@NonNull final Context context) {
        final PushChatApplication application = (PushChatApplication) context.getApplicationContext();
        return application.getUUID();
    }

    private Callback<RegistrationResponse> registrationCallback(
            @NonNull final Context context,
            @NonNull final String providerName,
            @NonNull final String registrationId
    ) {
        return new Callback<RegistrationResponse>() {
            @Override
            public void success(@NonNull final RegistrationResponse registrationResponse,
                                @NonNull final Response response) {
                OPFLog.logMethod(registrationResponse, response);

                StateController.putRegIdSavedOnServerValue(context, true);

                final Intent registeredIntent = new Intent(REGISTERED_ACTION);
                registeredIntent.putExtra(PROVIDER_NAME_EXTRA_KEY, providerName);
                registeredIntent.putExtra(Constants.REGISTRATION_ID_EXTRA_KEY, registrationId);
                context.sendBroadcast(registeredIntent);
                context.sendBroadcast(new Intent(HIDE_PROGRESS_BAR_ACTION));
            }

            @Override
            public void failure(@NonNull final RetrofitError error) {
                OPFLog.logMethod(error);
                OPFLog.e(error.getMessage());
                register(context, providerName, registrationId);
            }
        };
    }

    private Callback<UnregistrationResponse> unregistrationCallback(
            @NonNull final Context context
    ) {
        return new Callback<UnregistrationResponse>() {
            @Override
            public void success(@NonNull final UnregistrationResponse unregistrationResponse,
                                @NonNull final Response response) {
                OPFLog.logMethod(unregistrationResponse, response);

                StateController.putRegIdSavedOnServerValue(context, false);

                context.sendBroadcast(new Intent(UNREGISTERED_ACTION));
                context.sendBroadcast(new Intent(HIDE_PROGRESS_BAR_ACTION));
            }

            @Override
            public void failure(@NonNull final RetrofitError error) {
                OPFLog.logMethod(error);
                OPFLog.e(error.getMessage());
                unregister(context);
            }
        };
    }
} public class MessagesCursorAdapter extends CursorAdapter {

    private static final int TYPE_COUNT = 2;

    private static final int ODD_ITEM = 1;

    public MessagesCursorAdapter(@NonNull final Context context) {
        super(context, null, true);
    }

    @Override
    public int getItemViewType(final int position) {
        return position % 2;
    }

    @Override
    public int getViewTypeCount() {
        return TYPE_COUNT;
    }

    @Override
    public View newView(final Context context, final Cursor cursor, final ViewGroup parent) {
        final View view = LayoutInflater.from(context).inflate(R.layout.item_message, parent, false);

        if (getItemViewType(cursor.getPosition()) == ODD_ITEM) {
            view.setBackgroundResource(R.drawable.odd_message_item_selector);
        }

        return view;
    }

    @Override
    public void bindView(final View view, final Context context, final Cursor cursor) {
        final String senderUuid = cursor.getString(cursor.getColumnIndexOrThrow(SENDER_UUID));
        final String senderName = cursor.getString(cursor.getColumnIndexOrThrow(SENDER_NAME));
        final String message = cursor.getString(cursor.getColumnIndexOrThrow(MESSAGE));
        final long time = cursor.getLong(cursor.getColumnIndexOrThrow(RECEIVED_TIME));

        final TextView senderTextView = (TextView) view.findViewById(R.id.sender);
        final TextView messageTextView = (TextView) view.findViewById(R.id.message_text);
        final TextView timeTextView = (TextView) view.findViewById(R.id.time);

        if (TextUtils.isEmpty(senderName)) {
            senderTextView.setText(context.getString(R.string.sender_uuid_fmt, senderUuid));
        } else {
            senderTextView.setText(context.getString(R.string.sender_name_fmt, senderName, senderUuid));
        }
        messageTextView.setText(message);
        timeTextView.setText(context.getString(R.string.time_fmt, new Date(time).toString()));
    }
} public class AlertDialogFragment extends DialogFragment {

    public static final String TAG = AlertDialogFragment.class.getName();

    private static final String MESSAGE_BUNDLE_KEY = "MESSAGE_BUNDLE_KEY";

    private OnClickListener onClickListener;

    public static AlertDialogFragment newInstance(@NonNull final String message) {
        final AlertDialogFragment dialogFragment = new AlertDialogFragment();
        final Bundle arguments = new Bundle();
        arguments.putString(MESSAGE_BUNDLE_KEY, message);
        dialogFragment.setArguments(arguments);
        return dialogFragment;
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(final Bundle savedInstanceState) {
        final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getActivity());

        dialogBuilder.setMessage(getArguments().getString(MESSAGE_BUNDLE_KEY));

        if (onClickListener == null) {
            onClickListener = new OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dismiss();
                }
            };
        }

        dialogBuilder.setPositiveButton(android.R.string.ok, onClickListener);

        return dialogBuilder.create();
    }

    public void setOnClickListener(@NonNull final OnClickListener onClickListener) {
        this.onClickListener = onClickListener;
    }
} public static final String RECEIVED_TIME = "received_time"; public static final String LINE_SEPARATOR = System.getProperty("line.separator"); public static final String REGISTERED_ACTION = "org.onepf.pushchat.REGISTERED_ACTION"; public static final String UNREGISTERED_ACTION = "org.onepf.pushchat.UNREGISTERED_ACTION";
import android.content.BroadcastReceiver;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import org.onepf.pushchat.R;
import org.onepf.pushchat.controller.NotificationController;
import org.onepf.pushchat.controller.StateController;
import org.onepf.pushchat.db.ContentDescriptor.MessagesContract;
import org.onepf.pushchat.db.DatabaseHelper;
import org.onepf.pushchat.model.PushState;
import org.onepf.pushchat.model.db.Message;
import org.onepf.pushchat.model.response.push.FailedPushResult;
import org.onepf.pushchat.model.response.push.PushMessageResponse;
import org.onepf.pushchat.retrofit.NetworkController;
import org.onepf.pushchat.ui.adapter.MessagesCursorAdapter;
import org.onepf.pushchat.ui.dialog.AlertDialogFragment;
import retrofit.Callback;
import retrofit.RetrofitError;
import retrofit.client.Response;
import static android.content.Context.CLIPBOARD_SERVICE;
import static org.onepf.pushchat.db.ContentDescriptor.MessagesContract.MessageEntry.RECEIVED_TIME;
import static org.onepf.pushchat.utils.Constants.LINE_SEPARATOR;
import static org.onepf.pushchat.utils.Constants.REGISTERED_ACTION;
import static org.onepf.pushchat.utils.Constants.UNREGISTERED_ACTION;
/*
 * Copyright 2012-2015 One Platform Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.onepf.pushchat.ui.fragment.content;



/**
 * @author Roman Savin
 * @since 28.04.2015
 */
public class MessagesFragment extends BaseContentFragment {

    public static final int POSITION = 2;

    private MessagesCursorAdapter adapter;

    private EditText messageEditText;

    private Button sendButton;

    @Nullable
    private UpdateStateReceiver receiver;

    private MessagesLoaderCallbacks loaderCallbacks;

    @NonNull
    public static MessagesFragment newInstance() {
        return new MessagesFragment();
    }

    @Override
    public View onCreateView(@NonNull final LayoutInflater inflater,
                             @Nullable final ViewGroup container,
                             @Nullable final Bundle savedInstanceState) {
        final View view = inflater.inflate(R.layout.fragment_messages, container, false);

        showClearButton();
        initMessagesEditText(view);
        initMessagesList(view);
        initLoaderManager();

        registerReceiver();

        return view;
    }

    @Override
    public void onResume() {
        super.onResume();
        NotificationController.getInstance().setNeedShowNotification(false);
    }

    @Override
    public void onPause() {
        super.onPause();
        NotificationController.getInstance().setNeedShowNotification(true);
        hideKeyboard(getView());
    }

    @SuppressWarnings("AssignmentToNull")
    @Override
    public void onDestroyView() {
        super.onDestroyView();
        unregisterReceiver();
        hideClearButton();
        loaderCallbacks = null;
        messageEditText = null;
        sendButton = null;
        adapter = null;
    }

    @Override
    public int getTitleResId() {
        return R.string.title_messages_fragment;
    }

    @Override
    public int getPosition() {
        return POSITION;
    }

    private void initMessagesEditText(@NonNull final View view) {
        messageEditText = (EditText) view.findViewById(R.id.message_input);
        sendButton = (Button) view.findViewById(R.id.message_send_button);

        sendButton.setOnClickListener(onSendClickListener());

        final boolean isRegistered = StateController.getState(getActivity()) == PushState.REGISTERED;
        messageEditText.setEnabled(isRegistered);
        sendButton.setEnabled(isRegistered);
    }

    private void initMessagesList(@NonNull final View view) {
        final ListView messagesListView = (ListView) view.findViewById(R.id.messages_list);

        adapter = new MessagesCursorAdapter(getActivity());
        messagesListView.setAdapter(adapter);

        messagesListView.setOnItemLongClickListener(onItemLongClickListener());
    }

    private void initLoaderManager() {
        final LoaderManager loaderManager = getLoaderManager();
        loaderCallbacks = new MessagesLoaderCallbacks();
        loaderManager.initLoader(0, null, loaderCallbacks);
    }

    private View.OnClickListener onSendClickListener() {
        return new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (messageEditText == null) {
                    return;
                }

                //Action send. Perform checks and push message.
                final String messageText = messageEditText.getText().toString();
                if (TextUtils.isEmpty(messageText)) {
                    return;
                }

                final Context context = getActivity();
                if (DatabaseHelper.getInstance(context).isContactsTableEmpty()) {
                    //There aren't any contacts. Show dialog.
                    final AlertDialogFragment dialogFragment = AlertDialogFragment