package tv.dyndns.kishibe.qmaclone.client.lobby;
import static java.lang.String.valueOf;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import tv.dyndns.kishibe.qmaclone.client.PopupPanelEventRooms;
import tv.dyndns.kishibe.qmaclone.client.Service;
import tv.dyndns.kishibe.qmaclone.client.UserData;
import tv.dyndns.kishibe.qmaclone.client.constant.Constant;
import tv.dyndns.kishibe.qmaclone.client.game.ProblemGenre;
import tv.dyndns.kishibe.qmaclone.client.game.ProblemType;
import tv.dyndns.kishibe.qmaclone.client.packet.NewAndOldProblems;
import tv.dyndns.kishibe.qmaclone.client.packet.PacketPlayerSummary;
import tv.dyndns.kishibe.qmaclone.client.packet.PacketRankingData;
import tv.dyndns.kishibe.qmaclone.client.packet.PacketRoomKey;
import tv.dyndns.kishibe.qmaclone.client.packet.PacketServerStatus;
import tv.dyndns.kishibe.qmaclone.client.ui.WidgetMultiItemSelector;
import tv.dyndns.kishibe.qmaclone.client.util.CommandRunner;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.SpanElement;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FocusWidget;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
public class LobbyUi extends Composite {
private static final Logger logger = Logger.getLogger(LobbyUi.class.getName());
private static final LobbyUiUiBinder uiBinder = GWT.create(LobbyUiUiBinder.class);
private static LobbyUi instance = null;
private final SceneLobby scene;
// BugTrack-QMAClone/388 - QMAClone wiki
// http://kishibe.dyndns.tv/qmaclone/wiki/wiki.cgi?page=BugTrack%2DQMAClone%2F388#1322751108
// BugTrack-QMAClone/397
// http://kishibe.dyndns.tv/qmaclone/wiki/wiki.cgi?page=BugTrack-QMAClone%2F397
@VisibleForTesting
static final List<String> LEVEL_NAMES = ImmutableList.of("修練", "見習", "初級", "中級", "上級", "魔導",
"大魔導", "賢者", "大賢者", "青銅", "白銀", "黄金", "白金", "金剛", "天青", "紅玉", "翡翠", "黄玉", "紫宝", "琥珀", "瑠璃");
private static final String[][] DIFFICULTIES = {
{ "全難易度から出題する", valueOf(Constant.DIFFICULT_SELECT_NORMAL) },
{ "難問を出題する", valueOf(Constant.DIFFICULT_SELECT_DIFFICULT) },
{ "やや難問を出題する", valueOf(Constant.DIFFICULT_SELECT_LITTLE_DIFFICULT) },
{ "やや易問を出題する", valueOf(Constant.DIFFICULT_SELECT_LITTLE_EASY) },
{ "易問を出題する", valueOf(Constant.DIFFICULT_SELECT_EASY) }, };
@UiField
ListBox listBoxLevelNumber;
@UiField
ListBox listBoxLevelName;
@UiField
ListBox listBoxPrefecture;
@UiField
TextBox textBoxPlayerName;
@UiField(provided = true)
WidgetMultiItemSelector<ProblemGenre> multiItemSelectorGenre;
@UiField(provided = true)
WidgetMultiItemSelector<ProblemType> multiItemSelectorType;
@UiField
TextBox textBoxGreeting;
@UiField
ListBox listBoxDifficultSelect;
@UiField
ListBox listBoxNewProblem;
@UiField
Button buttonGameVsCom;
@UiField
Button buttonGameAllClass;
@UiField
Button buttonGameEvent;
@UiField
Button buttonGameTheme;
@UiField
TextBox textBoxEventName;
@UiField
Button buttonShowEventRooms;
@UiField
CheckBox checkBoxPublicEvent;
@UiField
ListBox listBoxTheme;
@UiField
SpanElement spanTopPageCount;
@UiField
SpanElement spanProblems;
@UiField
SpanElement spanTotalSessions;
@UiField
SpanElement spanCurrentSessions;
@UiField
SpanElement spanTotalPlayers;
@UiField
SpanElement spanCurrentPlayers;
@UiField
SpanElement spanLoginPlayers;
@UiField
SpanElement spanActivePlayers;
@UiField
SpanElement spanWaiting;
@UiField
SpanElement spanPlayCount;
@UiField
SpanElement spanHighScore;
@UiField
SpanElement spanAverageScore;
@UiField
SpanElement spanRating;
@UiField
SpanElement spanAverageRank;
@UiField
SpanElement spanClass;
@UiField
SpanElement spanUserCode;
@UiField
Button buttonShowUserCode;
@UiField
HTMLPanel panelInformation;
@UiField
SpanElement spanPlayerHistory;
@VisibleForTesting
boolean specialLevelName = false;
private final CommandRunner initializers = new CommandRunner(Arrays.asList(new Runnable() {
@Override
public void run() {
Service.Util.getInstance().getGeneralRanking(callbackGetRankingData);
}
}, new Runnable() {
public void run() {
Service.Util.getInstance().getThemeModeThemes(callbackGetThemeModeThemes);
}
}));
interface LobbyUiUiBinder extends UiBinder<Widget, LobbyUi> {
}
public LobbyUi(SceneLobby sceneRegistration) {
multiItemSelectorGenre = new WidgetMultiItemSelector<ProblemGenre>("ジャンル",
ProblemGenre.values(), 3);
multiItemSelectorType = new WidgetMultiItemSelector<ProblemType>("出題形式", ProblemType.values(),
4);
initWidget(uiBinder.createAndBindUi(this));
instance = this;
if (Constant.FIXED_CLASS_LEVEL >= 0) {
UserData.get().setClassLevel(Constant.FIXED_CLASS_LEVEL);
}
this.scene = sceneRegistration;
UserData record = UserData.get();
// 階級名
for (String levelName : LEVEL_NAMES) {
listBoxLevelName.addItem(levelName);
}
listBoxLevelName.addChangeHandler(levelNameChangeHandler);
int levelName = record.getLevelName();
if (levelName == Integer.MAX_VALUE) {
levelName = 0;
}
listBoxLevelName.setSelectedIndex(Math.min(levelName, listBoxLevelName.getItemCount() - 1));
// 階級の数字
for (int i = 1; i <= 10; ++i) {
listBoxLevelNumber.addItem(valueOf(i));
}
int levelNumber = record.getLevelNumber();
if (levelNumber == Integer.MAX_VALUE) {
levelNumber = 0;
}
listBoxLevelNumber.setSelectedIndex(levelNumber);
// 地域
for (String prefectureName : Constant.PREFECTURE_NAMES) {
listBoxPrefecture.addItem(prefectureName);
}
int prefecture = record.getPrefecture();
listBoxPrefecture.setSelectedIndex(prefecture);
// プレイヤー名入力
textBoxPlayerName.setText(record.getPlayerName());
// ジャンル選択
multiItemSelectorGenre.set(UserData.get().getGenre());
// 出題形式選択
multiItemSelectorType.set(UserData.get().getTypes());
// 挨拶
if (!record.getGreeting().isEmpty()) {
textBoxGreeting.setText(record.getGreeting());
}
// 難問の出題
for (String[] difficulty : DIFFICULTIES) {
String item = difficulty[0];
String value = difficulty[1];
listBoxDifficultSelect.addItem(item, value);
}
int difficultSelect = UserData.get().getDifficultSelect();
for (int i = 0; i < listBoxDifficultSelect.getItemCount(); ++i) {
if (difficultSelect == Integer.parseInt(listBoxDifficultSelect.getValue(i))) {
listBoxDifficultSelect.setSelectedIndex(i);
break;
}
}
// 新問の出題
listBoxNewProblem.setSelectedIndex(UserData.get().getNewAndOldProblems().ordinal());
// イベント
checkBoxPublicEvent.setValue(UserData.get().isPublicEvent());
setPlayerRecord();
// 情報パネル
updateInfomationPanel();
initializers.run();
}
private static final int[] SPECIAL_LEVEL_NAME_RANGE = { 0, 1, 5, 21, 50 };
private static final String[] SPECIAL_LEVEL_NAMES = { "賢神", "賢帝", "賢王", "賢将" };
private final AsyncCallback<List<List<PacketRankingData>>> callbackGetRankingData = new AsyncCallback<List<List<PacketRankingData>>>() {
@Override
public void onSuccess(List<List<PacketRankingData>> rankingData) {
updateSpecialLevelName(rankingData);
initializers.run();
}
@Override
public void onFailure(Throwable caught) {
logger.log(Level.WARNING, "ランキングの取得に失敗しました", caught);
initializers.run();
}
};
@VisibleForTesting
void updateSpecialLevelName(List<List<PacketRankingData>> rankingData) {
if (rankingData == null || rankingData.size() < 4) {
logger.log(Level.WARNING, "取得したランキング情報が壊れています");
return;
}
int userCode = UserData.get().getUserCode();
List<PacketRankingData> ratingRanking = rankingData.get(3);
for (int nameIndex = 0; !specialLevelName && nameIndex < 4; ++nameIndex) {
int begin = SPECIAL_LEVEL_NAME_RANGE[nameIndex];
int end = SPECIAL_LEVEL_NAME_RANGE[nameIndex + 1];
for (int i = begin; i < end; ++i) {
if (ratingRanking.size() <= i) {
continue;
}
if (userCode != ratingRanking.get(i).userCode) {
continue;
}
Preconditions.checkState(listBoxLevelName.getItemCount() == LEVEL_NAMES.size());
listBoxLevelName.addItem(SPECIAL_LEVEL_NAMES[nameIndex]);
listBoxLevelName.setSelectedIndex(listBoxLevelName.getItemCount() - 1);
listBoxLevelNumber.setEnabled(false);
listBoxLevelName.addChangeHandler(levelNameChangeHandler);
specialLevelName = true;
return;
}
}
}
@VisibleForTesting
final ChangeHandler levelNameChangeHandler = new ChangeHandler() {
@Override
public void onChange(ChangeEvent event) {
listBoxLevelNumber.setEnabled(listBoxLevelName.getSelectedIndex() < LEVEL_NAMES.size());
}
};
public static LobbyUi getInstance() {
return instance;
}
private final AsyncCallback<List<List<String>>> callbackGetThemeModeThemes = new AsyncCallback<List<List<String>>>() {
public void onSuccess(List<List<String>> result) {
updateThemeMode(result);
initializers.run();
}
public void onFailure(Throwable caught) {
logger.log(Level.WARNING, "テーマモード一覧の取得に失敗しました", caught);
initializers.run();
}
};
@VisibleForTesting
void updateThemeMode(List<List<String>> themeMode) {
listBoxTheme.clear();
listBoxTheme.addItem("テーマを選んでください", "");
int index = 1;
for (ProblemGenre genre : ProblemGenre.values()) {
listBoxTheme.addItem("", "");
listBoxTheme.addItem(genre.toString(), "");
List<String> themes = themeMode.get(genre.getIndex());
for (String theme : themes) {
String item = index++ + " " + theme;
String value = theme;
listBoxTheme.addItem(item, value);
}
}
for (int i = 0; i < listBoxTheme.getItemCount(); ++i) {
String value = listBoxTheme.getValue(i);
String theme = UserData.get().getTheme();
if (value.equals(theme)) {
listBoxTheme.setSelectedIndex(i);
break;
}
}
}
public void setPlayerRecord() {
UserData record = UserData.get();
int playCount = record.getPlayCount();
int highScore = record.getHighScore();
int averageScore = record.getAverageScore();
int rating = record.getRating();
double averageRank = record.getAverageRank();
int classLevel = record.getClassLevel();
int classNameIndex = classLevel / Constant.STEP_PER_CLASS_LEVEL;
if (classNameIndex >= Constant.MAX_CLASS_LEVEL) {
classNameIndex = Constant.MAX_CLASS_LEVEL;
}
if (record.getPlayCount() == Integer.MAX_VALUE) {
record.setPlayCount(0);
record.setHighScore(0);
record.setAverageScore(0);
record.setRating(0);
playCount = 0;
highScore = 0;
averageScore = 0;
rating = 0;
}
String averageRankString;
if (averageRank > 0.9) {
averageRankString = valueOf(averageRank);
if (averageRankString.length() > 4) {
averageRankString = averageRankString.substring(0, 4);
}
} else {
averageRankString = "未プレイ";
}
spanPlayCount.setInnerText(valueOf(playCount));
spanHighScore.setInnerText(valueOf(highScore));
spanAverageScore.setInnerText(valueOf(averageScore));
spanRating.setInnerText(valueOf(rating));
spanAverageRank.setInnerText(averageRankString);
spanClass.setInnerText("(" + classLevel + ")" + Constant.getClassName(classNameIndex) + "組");
}
@UiHandler("buttonGameVsCom")
void onButtonGameVsCom(ClickEvent e) {
register(e.getSource());
}
@UiHandler("buttonGameAllClass")
void onButtonGameAllClass(ClickEvent e) {
register(e.getSource());
}
@UiHandler("buttonGameEvent")
void onButtonGameEvent(ClickEvent e) {
register(e.getSource());
}
@UiHandler("buttonGameTheme")
void onButtonGameTheme(ClickEvent e) {
register(e.getSource());
}
@UiHandler("buttonShowEventRooms")
void onButtonShowEventRooms(ClickEvent e) {
showEventRooms();
}
@UiHandler("buttonShowUserCode")
void onButtonShowUserCode(ClickEvent e) {
spanUserCode.setInnerText(valueOf(UserData.get().getUserCode()));
buttonShowUserCode.setVisible(false);
}
public void updateInfomationPanel() {
panelInformation.setVisible(UserData.get().isShowInfo());
}
private void setEnabled(boolean enabled) {
FocusWidget[] widgets = { listBoxLevelNumber, listBoxLevelName, listBoxPrefecture,
textBoxPlayerName, textBoxGreeting, listBoxDifficultSelect, listBoxNewProblem,
buttonGameVsCom, buttonGameAllClass, buttonGameEvent, buttonGameTheme, textBoxEventName,
buttonShowEventRooms, checkBoxPublicEvent, listBoxTheme, buttonShowUserCode, };
for (FocusWidget widget : widgets) {
widget.setEnabled(enabled);
}
multiItemSelectorGenre.setEnabled(enabled);
multiItemSelectorType.setEnabled(enabled);
}
public void setLastestPlayers(List<PacketPlayerSummary> playerSummaries) {
StringBuilder sb = new StringBuilder();
for (PacketPlayerSummary playerSummary : playerSummaries) {
if (sb.length() != 0) {
sb.append('\n');
}
sb.append(playerSummary.level).append(' ').append(playerSummary.name);
}
spanPlayerHistory.setInnerHTML(new SafeHtmlBuilder().appendEscapedLines(sb.toString())
.toSafeHtml().asString());
}
private boolean checkContents() {
if (textBoxPlayerName.getText().trim().length() == 0) {
return false;
}
if (textBoxGreeting.getText().trim().length() == 0) {
return false;
}
if (multiItemSelectorGenre.get().isEmpty()) {
return false;
}
if (multiItemSelectorType.get().isEmpty()) {
return false;
}
return true;
}
public void setServerStatus(PacketServerStatus serverStatus) {
spanTotalSessions.setInnerText(valueOf(serverStatus.numberOfTotalSessions));
spanCurrentSessions.setInnerText(valueOf(serverStatus.numberOfCurrentSessions));
spanTotalPlayers.setInnerText(valueOf(serverStatus.numberOfTotalPlayers));
spanCurrentPlayers.setInnerText(valueOf(serverStatus.numberOfCurrentPlayers));
spanLoginPlayers.setInnerText(valueOf(serverStatus.numberOfLoginPlayers));
spanTopPageCount.setInnerText(valueOf(serverStatus.numberOfPageView));
spanProblems.setInnerText(valueOf(serverStatus.numberOfProblems));
spanActivePlayers.setInnerText(valueOf(serverStatus.numberOfActivePlayers));
spanWaiting.setInnerText(valueOf(serverStatus.numberOfPlayersInWhole));
setPlayerRecord();
}
public PacketPlayerSummary getPlayerSummary() {
PacketPlayerSummary player = new PacketPlayerSummary();
// 階級
player.level = listBoxLevelName.getItemText(listBoxLevelName.getSelectedIndex());
if (listBoxLevelName.getSelectedIndex() != LEVEL_NAMES.size()) {
player.level += listBoxLevelNumber.getItemText(listBoxLevelNumber.getSelectedIndex());
}
// プレイヤー名
player.name = textBoxPlayerName.getText();
if (player.name.length() > Constant.MAX_PLAYER_NAME_LENGTH) {
player.name = player.name.substring(0, Constant.MAX_PLAYER_NAME_LENGTH);
}
// 県
player.prefecture = Constant.PREFECTURE_NAMES[listBoxPrefecture.getSelectedIndex()];
// レーティング
player.rating = UserData.get().getRating();
return player;
}
public Set<ProblemGenre> getGenres() {
return multiItemSelectorGenre.get();
}
public void setGenres(Set<ProblemGenre> genres) {
multiItemSelectorGenre.set(genres);
}
public Set<ProblemType> getTypes() {
return multiItemSelectorType.get();
}
public void setTypes(Set<ProblemType> types) {
multiItemSelectorType.set(types);
}
public boolean getMultiGenre() {
return multiItemSelectorGenre.isMultiSelect();
}
public boolean getMultiType() {
return multiItemSelectorType.isMultiSelect();
}
public String getGreeting() {
return textBoxGreeting.getText();
}
public String getEventName() {
return textBoxEventName.getText();
}
public void setEventName(String eventName) {
textBoxEventName.setText(eventName);
}
public boolean getPublicEvent() {
return checkBoxPublicEvent.getValue();
}
public void setPublicEvent(boolean publicEvent) {
checkBoxPublicEvent.setValue(publicEvent);
}
public int getDifficultSelect() {
int selectedIndex = listBoxDifficultSelect.getSelectedIndex();
String selectedItem = listBoxDifficultSelect.getValue(selectedIndex);
return Integer.parseInt(selectedItem);
}
public NewAndOldProblems getNewAndOldProblems() {
return NewAndOldProblems.values()[listBoxNewProblem.getSelectedIndex()];
}
public void setNewProblem(NewAndOldProblems newProblem) {
listBoxNewProblem.setSelectedIndex(newProblem.ordinal());
}
public String getThemeModeTheme() {
int index = listBoxTheme.getSelectedIndex();
if (index == -1) {
return null;
}
return listBoxTheme.getValue(index);
}
private void showEventRooms() {
Service.Util.getInstance().getEventRooms(callbackGetEventRooms);
}
private final AsyncCallback<List<PacketRoomKey>> callbackGetEventRooms = new AsyncCallback<List<PacketRoomKey>>() {
public void onSuccess(List<PacketRoomKey> result) {
showEventRooms(result);
}
public void onFailure(Throwable caught) {
logger.log(Level.WARNING, "イベント部屋一覧の取得に失敗しました", caught);
}
};
private void showEventRooms(List<PacketRoomKey> eventRooms) {
PopupPanelEventRooms popup = new PopupPanelEventRooms(this, eventRooms);
popup.setPopupPosition(buttonShowEventRooms.getAbsoluteLeft(),
buttonShowEventRooms.getAbsoluteTop());
popup.show();
}
private void register(Object sender) {
// プレイヤー登録
if (!checkContents()) {
return;
}
if (sender == buttonGameEvent) {
StringBuilder sb = new StringBuilder();
sb.append("イベント名 : ").append(getEventName()).append("\n\nジャンル :");
for (ProblemGenre genre : getGenres()) {
sb.append(" ").append(genre.toString());
}
sb.append("\n\n形式 :");
for (ProblemType type : getTypes()) {
sb.append(" ").append(type.toString());
}
sb.append("\n\nこの条件でイベント戦を行ないます。\n同じ条件を指定したプレイヤーとのみマッチングします。\nよろしいですか?");
if (!Window.confirm(sb.toString())) {
return;
}
}
if (sender == buttonGameTheme) {
String themeModeTheme = getThemeModeTheme();
if (Strings.isNullOrEmpty(themeModeTheme)) {
return;
}
}
setEnabled(false);
saveUserData();
int sessionType;
if (sender == buttonGameVsCom) {
sessionType = SceneLobby.SESSION_TYPE_VS_COM;
} else if (sender == buttonGameAllClass) {
sessionType = SceneLobby.SESSION_TYPE_WHOLE;
} else if (sender == buttonGameEvent) {
sessionType = SceneLobby.SESSION_TYPE_EVENT;
} else if (sender == buttonGameTheme) {
sessionType = SceneLobby.SESSION_TYPE_THEME;
} else {
sessionType = SceneLobby.SESSION_TYPE_VS_COM;
}
// 全体戦では手書きクイズを出さない
Set<ProblemType> types = getTypes();
if (sessionType == SceneLobby.SESSION_TYPE_WHOLE) {
types.remove(ProblemType.Tegaki);
}
if (types.isEmpty()) {
Window.alert("手書きクイズはβ版のため全体対戦ではお使いいただけません");
setEnabled(true);
return;
}
setTypes(types);
scene.register(sessionType);
}
@VisibleForTesting
void saveUserData() {
UserData record = UserData.get();
record.setPlayerName(textBoxPlayerName.getText().trim());
record.setLevelName(listBoxLevelName.getSelectedIndex());
record.setLevelNumber(listBoxLevelNumber.getSelectedIndex());
record.setPrefecture(listBoxPrefecture.getSelectedIndex());
record.setGenres(getGenres());
record.setTypes(getTypes());
record.setGreeting(getGreeting());
record.setMultiGenre(getMultiGenre());
record.setMultiType(getMultiType());
record.setDifficultSelect(getDifficultSelect());
record.setNewAndOldProblems(getNewAndOldProblems());
record.setPublicEvent(getPublicEvent());
record.setTheme(getThemeModeTheme());
record.save();
}
}