/*
* MIT License
*
* Copyright (c) 2017 Lam Tran (tranngoclam288@gmail.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.lamtran.moviebooking.presentation.view.theatre;
import android.content.Intent;
import android.databinding.ObservableInt;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.widget.PopupMenu;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import dagger.Binds;
import io.github.lamtran.moviebooking.R;
import io.github.lamtran.moviebooking.data.model.theatre.Theatre;
import io.github.lamtran.moviebooking.data.model.theatre.seat.ChosenSeat;
import io.github.lamtran.moviebooking.data.model.theatre.seat.EmptySeat;
import io.github.lamtran.moviebooking.data.model.theatre.seat.ReservedSeat;
import io.github.lamtran.moviebooking.data.model.theatre.seat.Seat;
import io.github.lamtran.moviebooking.data.model.theatre.seat.UnChosenSeat;
import io.github.lamtran.moviebooking.databinding.ActivityTheatreBinding;
import io.github.lamtran.moviebooking.internal.injection.scope.ForActivity;
import io.github.lamtran.moviebooking.presentation.App;
import io.github.lamtran.moviebooking.presentation.util.TheatreUtils;
import io.github.lamtran.moviebooking.presentation.util.Toaster;
import io.github.lamtran.moviebooking.presentation.view.base.screen.BaseActivity;
import io.github.lamtran.moviebooking.presentation.view.theatre.seat.SeatAdapter;
import io.github.lamtran.moviebooking.presentation.view.theatre.seat.SeatChanger;
import java.util.List;
import javax.inject.Inject;
import static android.view.KeyEvent.KEYCODE_BACK;
import static io.github.lamtran.moviebooking.presentation.util.TheatreUtils.swapSeat;
import static io.github.lamtran.moviebooking.presentation.util.TheatreUtils.swapSeatAlt;
/**
* Author: JONATHAN MERRITT
* Year: 2017
* Contact: 11R00TT00RR11@GMAIL.COM
*/
public class TheatreActivity extends BaseActivity<ActivityTheatreBinding, TheatreActivity.Controller> {
@Override public int getLayout() {
return R.layout.activity_theatre;
}
@Override public void setBindings(ActivityTheatreBinding binding) {
binding.setController(controller);
}
@Override public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_theatre, menu);
return super.onCreateOptionsMenu(menu);
}
@Override public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.item_github:
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(App.GITHUB)));
break;
case R.id.item_reset:
controller.reset();
break;
}
return super.onOptionsItemSelected(item);
}
@Override public boolean onKeyDown(int code, KeyEvent event) {
if (code == KEYCODE_BACK && controller.hasChosen()) {
controller.changeSeats(UnChosenSeat.class);
return true;
}
return super.onKeyDown(code, event);
}
@ForActivity public static class Controller extends BaseActivity.Controller<Theatre> {
public final ObservableInt unchosen = new ObservableInt(), chosen = new ObservableInt(), reserved =
new ObservableInt(), empty = new ObservableInt();
public final SeatAdapter adapter;
private final Toaster toaster;
@Inject public Controller(SeatAdapter adapter, Toaster toaster, SeatChanger changer) {
super();
this.adapter = adapter;
this.toaster = toaster;
changer.setRequester(this::changeSeat);
}
@Override public void onStart() {
super.onStart();
setModel(Theatre.idle(TheatreUtils.seats()));
adapter.setModels(model.seats());
}
@Override public void onRestore(Bundle restoredState) {
super.onRestore(restoredState);
adapter.setModels(model.seats());
}
@Override public void setModel(Theatre model) {
super.setModel(model);
unchosen.set(model.unchosen());
chosen.set(model.chosen());
reserved.set(model.reserved());
empty.set(model.empty());
}
@Override public void onClick(View view) {
super.onClick(view);
final int id = view.getId();
switch (id) {
case R.id.seat_click:
case R.id.seat_long_click:
case R.id.set_tickets:
final PopupMenu popup = new PopupMenu(view.getContext(), view);
for (int index = 0;
index < (id != R.id.set_tickets ? model.seats().size() : unchosen.get() + chosen.get()); index++) {
final Menu menu = popup.getMenu();
final int number = index + 1;
final String title = id == R.id.set_tickets && model.tickets() == number ? "Current " : "";
menu.add(id, number, index, String.format("%s%s", title, number));
}
popup.setOnMenuItemClickListener(item -> {
switch (id) {
case R.id.seat_click:
case R.id.seat_long_click:
final Seat last = model.seats().get(item.getOrder());
final Class<? extends Seat> lastClass = last.getClass();
changeSeat(last, id == R.id.seat_click ? swapSeat(lastClass) : swapSeatAlt(lastClass));
break;
case R.id.set_tickets:
setModel(Theatre.tickets(model, item.getItemId()));
if (model.tickets() < chosen.get()) changeSeats(UnChosenSeat.class);
break;
}
return true;
});
popup.show();
break;
case R.id.change_unchosen_to_chosen:
if (model.tickets() == chosen.get()) toaster.show(R.string.no_tickets_left);
else if (unchosen.get() > 0) changeSeats(ChosenSeat.class);
else toaster.show(R.string.no_unchosen_seats);
break;
case R.id.change_chosen_to_unchosen:
case R.id.change_chosen_to_reserved:
case R.id.change_chosen_to_empty:
if (hasChosen()) changeSeats(id == R.id.change_chosen_to_unchosen ? UnChosenSeat.class
: id == R.id.change_chosen_to_reserved ? ReservedSeat.class : EmptySeat.class);
else toaster.show(R.string.no_chosen_seats);
break;
}
}
private void changeSeat(Seat last, Class<? extends Seat> nextClass) {
if (model.tickets() <= chosen.get() && ChosenSeat.check(nextClass)) toaster.show(R.string.no_tickets_left);
else setModel(Theatre.seat(model, adapter.replace(last, nextClass), last.getClass(), nextClass));
}
private void changeSeats(Class<? extends Seat> nextClass) {
final boolean nextChosen = ChosenSeat.check(nextClass);
final Seat[] lasts = new Seat[nextChosen ? unchosen.get() : chosen.get()];
int total = 0, changes = total;
final List<Seat> seats = model.seats();
final int size = seats.size();
if (total < size) {
do {
final Seat last = seats.get(total);
final Class<? extends Seat> lastClass = last.getClass();
if ((nextChosen ? UnChosenSeat.check(lastClass) : ChosenSeat.check(lastClass)) && (!nextChosen
|| chosen.get() + changes < model.tickets())) {
lasts[changes] = last;
changes++;
}
total++;
} while (total < size);
}
for (int index = 0; index < changes; index++) changeSeat(lasts[index], nextClass);
}
private void reset() {
setModel(Theatre.reset(model, TheatreUtils.seats()));
adapter.setModels(model.seats());
}
private boolean hasChosen() {
return chosen.get() > 0;
}
}
@dagger.Module(includes = { SeatAdapter.Module.class }) public abstract class Module {
@ForActivity @Binds abstract BaseActivity baseActivity(TheatreActivity activity);
}
}