public class RatingDialogLaterEvent {
} public class RatingDialogNoEvent {
} public class RatingDialogYesEvent {
} public class SuggestDialogNoEvent {
} public class SuggestDialogYesEvent {
} @EBean
public class RatingHelper {
    private static final int THRESHOLD = 3;

    @RootContext
    Activity activity;

    @Pref
    RatePrefs_ ratePrefs;

    @Bean
    RatingDialogHelper ratingDialogHelper;

    @DebugLog
    public void increaseStartupCount() {
        ratePrefs.totalStartupCount().put(ratePrefs.totalStartupCount().get() + 1);
        ratePrefs.currentStartupCount().put(ratePrefs.currentStartupCount().get() + 1);
    }

    public void displaySuggestDialogIfNeeded() {
        boolean shouldAsk = ratePrefs.shouldAskAgain().get();
        int totalStartupCount = ratePrefs.totalStartupCount().get();
        int currentStartupCount = ratePrefs.currentStartupCount().get();

        if (shouldAsk && currentStartupCount >= THRESHOLD) {
            if (totalStartupCount > currentStartupCount) {
                ratingDialogHelper.displayRatingDialog();
            } else {
                ratingDialogHelper.displaySuggestDialog();
            }
        }
    }

    public void displayRatingDialog() {
        ratingDialogHelper.displayRatingDialog();
    }

    public void onRate() {
        final String packageName = getReleasePackageName();
        Uri uri = Uri.parse("market://details?id=" + packageName);
        Intent intent = getViewIntent(uri);

        try {
            activity.startActivity(intent);
            onRated();

        } catch (ActivityNotFoundException e) {
            uri = Uri.parse("http://play.google.com/store/apps/details?id=" + packageName);
            intent = new Intent(Intent.ACTION_VIEW, uri);
            activity.startActivity(intent);
            onRated();
        }
    }

    @DebugLog
    private String getReleasePackageName() {
        String packageName = activity.getPackageName();
        String buildType = BuildConfig.BUILD_TYPE;
        String buildTypeSuffix = "." + buildType;
        boolean notReleaseBuild = !"release".equals(buildType);

        if (notReleaseBuild && packageName.endsWith(buildTypeSuffix)) {
            packageName = packageName.replace(buildTypeSuffix, "");
        }

        return packageName;
    }

    @DebugLog
    private Intent getViewIntent(Uri uri) {
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        setFlags(intent);

        return intent;
    }

    private void setFlags(Intent intent) {
        intent.addFlags(
                Intent.FLAG_ACTIVITY_NO_HISTORY |
                        Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET |
                        Intent.FLAG_ACTIVITY_MULTIPLE_TASK
        );
    }

    @DebugLog
    public void onRated() {
        ratePrefs.shouldAskAgain().put(false);
    }

    @DebugLog
    public void onRateLater() {
        ratePrefs.shouldAskAgain().put(true);
        ratePrefs.currentStartupCount().put(0);
    }

    @DebugLog
    public void onDontAskAgain() {
        ratePrefs.shouldAskAgain().put(false);
    }
} @EBean
public class DisplayHelper {
    private Display display;

    @SystemService
    WindowManager windowManager;

    @AfterInject
    protected void init() {
        display = windowManager.getDefaultDisplay();
    }

    public Point getDisplaySize() {
        Point size = new Point();
        display.getSize(size);

        return size;
    }

    public int getScreenOrientation() {
        return display.getRotation();
    }

    public boolean isPortrait() {
        return !isLandscape();
    }

    public boolean isLandscape() {
        int rotation = display.getRotation();

        return (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270);
    }

    @NonNull
    public DisplayMetrics getDisplayMetrics() {
        DisplayMetrics metrics = new DisplayMetrics();
        windowManager.getDefaultDisplay().getMetrics(metrics);

        return metrics;
    }

    public int dpToPx(int dp) {
        DisplayMetrics metrics = getDisplayMetrics();

        return (int) (dp * metrics.density);
    }

    public int pxToDp(int px) {
        DisplayMetrics metrics = getDisplayMetrics();

        return (int) (px / metrics.density);
    }
} @EFragment
public class ChangeRulesDialogFragment extends DialogFragment {
    @InstanceState
    NeighborCountBasedRule rule;

    @Bean
    ChangeRulesDialogUiHelper uiHelper;

    Spinner presets;
    TableRow survivalCheckBoxes;
    TableRow creationCheckBoxes;
    View infoWrapperTitle;
    View infoWrapper;
    TextView type;
    TextView info;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        uiHelper.setFragment(this);
    }

    public void setRule(NeighborCountBasedRule rule) {
        this.rule = new NeighborCountBasedRule(rule);
        onRuleSet();
    }

    public NeighborCountBasedRule getRule() {
        return rule;
    }

    private void onRuleSet() {
        if (getDialog() != null) {
            initCheckboxes();
            uiHelper.selectMatchingPresetOrShowCustom();
        }
    }

    private void onCheckboxClicked() {
        NeighborCountBasedRule customRule = uiHelper.createRuleFromCheckboxStates();
        setRule(customRule);
    }

    private void onPresetSelected(Preset preset) {
        NeighborCountBasedRule presetRule = preset.getRule();

        if (presetRule != null && !rule.equals(presetRule)) {
            setRule(presetRule);
            uiHelper.showTypeInfo(preset);
        }
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        View view = initViews();
        initInfo();
        initPresets();
        initCheckboxes();

        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder
            .setView(view)
            .setTitle(R.string.dialog_change_rules_title)
            .setPositiveButton(android.R.string.ok, getOkListener())
            .setNegativeButton(android.R.string.cancel, getCancelListener())
        ;

        return builder.create();
    }

    @NonNull
    protected View initViews() {
        LayoutInflater inflater = getActivity().getLayoutInflater();
        View view = inflater.inflate(R.layout.dialog_change_rules, null);
        presets = (Spinner) view.findViewById(R.id.presets);
        survivalCheckBoxes = (TableRow) view.findViewById(R.id.survivalCheckBoxes);
        creationCheckBoxes = (TableRow) view.findViewById(R.id.creationCheckBoxes);
        infoWrapperTitle = view.findViewById(R.id.infoWrapperTitle);
        infoWrapper = view.findViewById(R.id.infoWrapper);
        type = (TextView) view.findViewById(R.id.type);
        info = (TextView) view.findViewById(R.id.info);

        return view;
    }

    protected void initInfo() {
        info.setClickable(true);
        info.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                uiHelper.showInfoDialog();
            }
        });
    }

    protected void initPresets() {
        presets.setAdapter(new PresetAdapter(getActivity()));
        presets.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> adapter, View view, int position, long id) {
                onPresetSelected((Preset) adapter.getItemAtPosition(position));
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {}
        });
    }

    protected void initCheckboxes() {
        for (int i = 0; i < 9; i++) {
            initCheckBox(i, survivalCheckBoxes, rule.getSurvivalNbCounts());
            initCheckBox(i, creationCheckBoxes, rule.getCreationNbCounts());
        }
    }

    protected void initCheckBox(final int i, TableRow checkBoxes, Set<Integer> nbCounts) {
        final CheckBox checkBox = (CheckBox) checkBoxes.getChildAt(i);
        checkBox.setChecked(rule != null && nbCounts.contains(i));
        setOnClickListener(checkBox);
    }

    private void setOnClickListener(CheckBox checkBox) {
        checkBox.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onCheckboxClicked();
            }
        });
    }

    @NonNull
    protected DialogInterface.OnClickListener getOkListener() {
        return new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int id) {
                EventBus.getInstance().post(rule);
                getDialog().dismiss();
            }
        };
    }

    @NonNull
    protected DialogInterface.OnClickListener getCancelListener() {
        return new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                getDialog().cancel();
            }
        };
    }

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

        uiHelper.setWidth();
        uiHelper.selectMatchingPresetOrShowCustom();
    }
} public interface Cell {
    public static final int STATE_ALIVE = 1;
    public static final int STATE_DEAD = 0;

    void reset(int state);
    long getId();
    int getY();
    int getX();
    void setState(int state);
    int getState();
    boolean isAlive();
    boolean isDead();
    void onNeighborStateChange(int newState);
    void setOverseer(Overseer overseer);
} public class Fill {
    private final float percentage;
    private final int state;

    public Fill(float percentage, int state) {
        this.percentage = percentage;
        this.state = state;
    }

    public float getPercentage() {
        return percentage;
    }

    public int getState() {
        return state;
    }
} public class GameOfLifeFactory implements CellularAutomatonFactory {
    @Override
    public CellularAutomaton<?> create(int gridSizeX, int gridSizeY) {
        return new GameOfLife(gridSizeX, gridSizeY);
    }
} public class Pause {
} public class Reset {
} public class Restart {
} public class Resume {
} public class GameManager {
    public static final String KEY_AUTOMATON = "automaton";
    private final AutomatonView automatonView;
    private CellularAutomaton automaton;
    private GameParams params;

    public GameManager(Bundle savedGameState, AutomatonView automatonView, CellularAutomatonFactory factory, GameParams params) {
        this.automatonView = automatonView;
        this.params = params;

        if (savedGameState != null) {
            restoreGameState(savedGameState);

        } else {
            this.automaton = createAutomaton(factory, params);
        }
    }

    private CellularAutomaton createAutomaton(CellularAutomatonFactory factory, GameParams params) {
        CellularAutomaton<?> automaton = factory.create(
                params.getGridSizeX(),
                params.getGridSizeY()
        );

        automaton.randomFill(params.getFill());

        return automaton;
    }

    public CellularAutomaton getAutomaton() {
        return automaton;
    }

    public void createGame() {
        initView(
                automatonView,
                automaton,
                params
        );
    }

    private static void initView(AutomatonView automatonView, CellularAutomaton automaton, GameParams params) {
        automatonView.init(
                automaton,
                params
        );
    }

    public Bundle saveGameState() {
        Bundle gameState = new Bundle();
        gameState.putParcelable(KEY_AUTOMATON, getAutomaton());

        return gameState;
    }

    public void restoreGameState(Bundle gameState) {
        automaton = gameState.getParcelable(KEY_AUTOMATON);
    }
} public class GameParams {
    private final int screenOrientation;
    private final Point displaySize;
    private int gridSizeX;
    private int gridSizeY;
    private final int cellSizeInPixels;
    private final Fill fill;
    private final CellColors cellColors;
    private final int fps;
    private final boolean startPaused;

    public GameParams(int screenOrientation, Point displaySize, int cellSizeInPixels, Fill fill, CellColors cellColors, int fps, boolean startPaused) {
        this.screenOrientation = screenOrientation;
        this.displaySize = displaySize;
        gridSizeX = displaySize.x / cellSizeInPixels;
        gridSizeY = displaySize.y / cellSizeInPixels;
        this.cellSizeInPixels = cellSizeInPixels;
        this.fill = fill;
        this.cellColors = cellColors;
        this.fps = fps;
        this.startPaused = startPaused;
    }

    public int getScreenOrientation() {
        return screenOrientation;
    }

    public Point getDisplaySize() {
        return displaySize;
    }

    public int getGridSizeX() {
        return gridSizeX;
    }

    public int getGridSizeY() {
        return gridSizeY;
    }

    public int getCellSizeInPixels() {
        return cellSizeInPixels;
    }

    public Fill getFill() {
        return fill;
    }

    public CellColors getCellColors() {
        return cellColors;
    }

    public int getFps() {
        return fps;
    }

    public boolean startPaused() {
        return startPaused;
    }
} public class GameParamsBuilder {
    private int screenOrientation;
    private Point displaySize;
    private int cellSizeInPixels;
    private Fill fill;
    private CellColors cellColors;
    private int fps;
    private boolean startPaused;

    public static GameParamsBuilder create() {
        return new GameParamsBuilder();
    }

    public GameParamsBuilder setScreenOrientation(int screenOrientation) {
        this.screenOrientation = screenOrientation;
        return this;
    }

    public GameParamsBuilder setDisplaySize(Point displaySize) {
        this.displaySize = displaySize;
        return this;
    }

    public GameParamsBuilder setCellSizeInPixels(int cellSizeInPixels) {
        this.cellSizeInPixels = cellSizeInPixels;
        return this;
    }

    public GameParamsBuilder setFill(Fill fill) {
        this.fill = fill;
        return this;
    }

    public GameParamsBuilder setCellColors(CellColors cellColors) {
        this.cellColors = cellColors;
        return this;
    }

    public GameParamsBuilder setFps(int fps) {
        this.fps = fps;
        return this;
    }

    public GameParamsBuilder startPaused(boolean startPaused) {
        this.startPaused = startPaused;
        return this;
    }

    public GameParams build() {
        return new GameParams(screenOrientation, displaySize, cellSizeInPixels, fill, cellColors, fps, startPaused);
    }
} public class NeighborCountBasedRule implements Rule<SimpleCell> {
    private final Set<Integer> survivalNbCounts;
    private final Set<Integer> creationNbCounts;

    public NeighborCountBasedRule(Set<Integer> survivalNbCounts, Set<Integer> creationNbCounts) {
        this.survivalNbCounts = new HashSet<>(survivalNbCounts);
        this.creationNbCounts = new HashSet<>(creationNbCounts);
    }

    public NeighborCountBasedRule(String rule) {
        String[] split = rule.split("/");
        if (split.length != 2) {
            throw new IllegalArgumentException("Invalid rule string: " + rule);
        }

        try {
            survivalNbCounts = new HashSet<>();
            String survival = split[0];
            for (int i = 0; i < survival.length(); i++) {
                survivalNbCounts.add(Integer.valueOf(String.valueOf(survival.charAt(i))));
            }

            creationNbCounts = new HashSet<>();
            String creation = split[1];
            for (int i = 0; i < creation.length(); i++) {
                creationNbCounts.add(Integer.valueOf(String.valueOf(creation.charAt(i))));
            }

        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("Invalid rule string: " + rule);
        }
    }

    public NeighborCountBasedRule(NeighborCountBasedRule other) {
        this.survivalNbCounts = new HashSet<>(other.survivalNbCounts);
        this.creationNbCounts = new HashSet<>(other.creationNbCounts);
    }

    @Override
    public int apply(Grid<SimpleCell> grid, int x, int y) {
        SimpleCell current = grid.getCell(x, y);
        int n = current.getNeighborCount();

        if (grid.getCell(x, y).isAlive()) {
            return staysAlive(n);

        } else {
            return getsCreated(n);
        }

    }

    private int staysAlive(int n) {
        if (survivalNbCounts.contains(n)) {
            return Cell.STATE_ALIVE;

        } else {
            return Cell.STATE_DEAD;
        }
    }

    private int getsCreated(int n) {
        if (creationNbCounts.contains(n)) {
            return Cell.STATE_ALIVE;

        } else {
            return Cell.STATE_DEAD;
        }
    }

    public Set<Integer> getSurvivalNbCounts() {
        return survivalNbCounts;
    }

    public Set<Integer> getCreationNbCounts() {
        return creationNbCounts;
    }

    public void toggleSurvivalForNbCount(int nbCount) {
        if (survivalNbCounts.contains(nbCount)) {
            survivalNbCounts.remove(nbCount);
        } else {
            survivalNbCounts.add(nbCount);
        }
    }

    public void toggleCreationForNbCount(int nbCount) {
        if (creationNbCounts.contains(nbCount)) {
            creationNbCounts.remove(nbCount);
        } else {
            creationNbCounts.add(nbCount);
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        NeighborCountBasedRule that = (NeighborCountBasedRule) o;

        if (!survivalNbCounts.equals(that.survivalNbCounts)) return false;
        if (!creationNbCounts.equals(that.creationNbCounts)) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = survivalNbCounts.hashCode();
        result = 31 * result + creationNbCounts.hashCode();

        return result;
    }
} public class SimpleCellColors extends AbstractCellColors {
    public SimpleCellColors() {
        super();
        paintMap.put(Cell.STATE_DEAD, createPaint("#000000"));
        paintMap.put(Cell.STATE_ALIVE, createPaint("#ff9900"));
    }

} public class EventBus extends Bus {
    private static EventBus instance;

    private EventBus() {
        super(ThreadEnforcer.ANY);
    }

    public static EventBus getInstance() {
        if (instance == null) {
            instance = new EventBus();
        }

        return instance;
    }

    @Override
    public void unregister(Object object) {
        try {
            super.unregister(object);

        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        }
    }
}
import android.graphics.Point;
import android.os.Bundle;
import com.squareup.otto.Subscribe;
import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EBean;
import org.androidannotations.annotations.RootContext;
import hu.supercluster.gameoflife.app.rate.event.RatingDialogLaterEvent;
import hu.supercluster.gameoflife.app.rate.event.RatingDialogNoEvent;
import hu.supercluster.gameoflife.app.rate.event.RatingDialogYesEvent;
import hu.supercluster.gameoflife.app.rate.event.SuggestDialogNoEvent;
import hu.supercluster.gameoflife.app.rate.event.SuggestDialogYesEvent;
import hu.supercluster.gameoflife.app.rate.util.RatingHelper;
import hu.supercluster.gameoflife.app.util.DisplayHelper;
import hu.supercluster.gameoflife.app.view.ChangeRulesDialogFragment;
import hu.supercluster.gameoflife.app.view.ChangeRulesDialogFragment_;
import hu.supercluster.gameoflife.game.cell.Cell;
import hu.supercluster.gameoflife.game.cellularautomaton.Fill;
import hu.supercluster.gameoflife.game.cellularautomaton.GameOfLifeFactory;
import hu.supercluster.gameoflife.game.event.Pause;
import hu.supercluster.gameoflife.game.event.Reset;
import hu.supercluster.gameoflife.game.event.Restart;
import hu.supercluster.gameoflife.game.event.Resume;
import hu.supercluster.gameoflife.game.manager.GameManager;
import hu.supercluster.gameoflife.game.manager.GameParams;
import hu.supercluster.gameoflife.game.manager.GameParamsBuilder;
import hu.supercluster.gameoflife.game.rule.NeighborCountBasedRule;
import hu.supercluster.gameoflife.game.visualization.cell.SimpleCellColors;
import hu.supercluster.gameoflife.util.EventBus;
import hugo.weaving.DebugLog;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
package hu.supercluster.gameoflife.app.activity.main;






@EBean
public class MainPresenter {
    GameManager gameManager;

    @RootContext
    MainActivity activity;

    @Bean
    DisplayHelper displayHelper;

    @Bean
    RatingHelper ratingHelper;

    void onActivityCreate() {
        if (!orientationChanged()) {
            ratingHelper.increaseStartupCount();
        }

        saveOrientation();
    }

    private boolean orientationChanged() {
        return displayHelper.getScreenOrientation() != activity.lastOrientation;
    }

    private void saveOrientation() {
        activity.lastOrientation = displayHelper.getScreenOrientation();
    }

    void onActivityResume() {
        EventBus.getInstance().register(this);
        ratingHelper.displaySuggestDialogIfNeeded();
    }

    void onActivityPause() {
        EventBus.getInstance().unregister(this);
    }

    public Bundle saveGameState() {
        return gameManager.saveGameState();
    }

    void startGame() {
        gameManager = new GameManager(
                activity.gameState,
                activity.automatonView,
                new GameOfLifeFactory(),
                getGameParams()
        );

        gameManager.createGame();

        if (activity.paused) {
            onPause();
        }
    }

    private GameParams getGameParams() {
        Point displaySize = displayHelper.getDisplaySize();
        int cellSize = getOptimalCellSize(displaySize, displayHelper.isLandscape());

        return GameParamsBuilder.create()
                .setScreenOrientation(displayHelper.getScreenOrientation())
                .setDisplaySize(displaySize)
                .setCellSizeInPixels(cellSize)
                .setFill(new Fill(0.10f, Cell.STATE_ALIVE))
                .setCellColors(new SimpleCellColors())
                .setFps(15)
                .startPaused(activity.paused)
                .build()
        ;
    }

    private int getOptimalCellSize(Point displaySize, boolean isLandscape) {
        int cellSize = 1;
        int limitX = 160;
        int limitY = 200;

        if (isLandscape) {
            int temp = limitX;
            limitX = limitY;
            limitY = temp;
        }

        while (displaySize.x / cellSize > limitX || displaySize.y / cellSize > limitY) {
            cellSize++;
        }

        return cellSize;
    }

    void onPause() {
        EventBus.getInstance().post(new Pause());
        setUiPausedState(true);
    }

    void onResume() {
        EventBus.getInstance().post(new Resume());
        setUiPausedState(false);
    }

    private void setUiPausedState(boolean paused) {
        activity.resume.setVisibility(paused ? VISIBLE : GONE);
        activity.pause.setVisibility(paused ? GONE : VISIBLE);
        activity.paused = paused;
    }

    void onResetGame() {
        onPause();
        EventBus.getInstance().post(new Reset());
    }

    void onRestartGame() {
        EventBus.getInstance().post(new Restart());
    }

    void onChangeRules() {
        ChangeRulesDialogFragment dialogFragment = ChangeRulesDialogFragment_.builder().build();
        dialogFragment.setRule((NeighborCountBasedRule) gameManager.getAutomaton().getRule());
        dialogFragment.show(activity.getFragmentManager(), "rules");
    }

    @DebugLog
    @Subscribe
    public void onRulesChanged(NeighborCountBasedRule rule) {
        gameManager.getAutomaton().setRule(rule);
    }

    @DebugLog
    @Subscribe
    public void onEvent(SuggestDialogYesEvent event) {
        ratingHelper.displayRatingDialog();
    }

    @DebugLog
    @Subscribe
    public void onEvent(SuggestDialogNoEvent event) {
        ratingHelper.onDontAskAgain();
    }

    @DebugLog
    @Subscribe
    public void onEvent(RatingDialogYesEvent event) {