/*
* Copyright 2015 Daniel Dittmar
*
* 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 dan.dit.whatsthat.testsubject.shopping;
import android.content.res.Resources;
import android.support.annotation.ArrayRes;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import dan.dit.whatsthat.R;
import dan.dit.whatsthat.testsubject.ForeignPurse;
import dan.dit.whatsthat.testsubject.TestSubject;
/**
* Created by daniel on 03.10.15.
*/
public class ShopArticleMulti extends ShopArticle {
private final int mProductDescrResId;
private int[] mCosts;
private MultiProduct[] mProducts;
/**
* Creates a new shop article with multiple sub products. There can be at most 31 subproducts, the amount is being defined
* by the size of the given costs array. The products are supposed to be improvements of each other and are required that the previous one
* is already purchased as a dependency.
* @param key The article's key identifying it..
* @param purse The purse to load and save purchase state from/to.
* @param nameResId The name resource id of this article's name.
* @param descrResId The description resource id of this article.
* @param iconResId The icon for the article.
* @param productDescrResId A string array resource for each product. Should be of size equal to given costs.
* @param costs The costs for each sub product.
*/
public ShopArticleMulti(@NonNull String key, @NonNull ForeignPurse purse, @StringRes int nameResId, @StringRes int descrResId, @DrawableRes int iconResId,
@ArrayRes int productDescrResId, int[] costs) {
super(key, purse, nameResId, descrResId, iconResId);
mCosts = costs;
mProductDescrResId = productDescrResId;
if (mCosts == null || mCosts.length == 0) {
throw new IllegalArgumentException("No costs given.");
}
mProducts = new MultiProduct[mCosts.length];
}
@Override
public void makeDependencies() {
super.makeDependencies();
for (int i = 1; i < mProducts.length; i++) {
addDependency(TestSubject.getInstance().makeProductPurchasedDependency(mKey, i - 1), i);
}
}
private int getPurchasedCount() {
int shopValue = mPurse.getShopValue(mKey);
return getSetBitsCount(shopValue);
}
public static boolean hasPurchased(int value, int index) {
return ((value >>> index) & 1) == 1;
}
private boolean isPurchased(int subProductIndex) {
int shopValue = mPurse.getShopValue(mKey);
return hasPurchased(shopValue, subProductIndex);
}
private int getSetBitsCount(int value) {
// http://stackoverflow.com/questions/109023/how-to-count-the-number-of-set-bits-in-a-32-bit-integer
value = value - ((value >>> 1) & 0x55555555);
value = (value & 0x33333333) + ((value >>> 2) & 0x33333333);
return (((value + (value >>> 4)) & 0x0F0F0F0F) * 0x01010101) >>> 24;
}
private int getMaxPurchaseCount() {
return mCosts.length;
}
@Override
public int isPurchasable(int subProductIndex) {
if (isPurchased(subProductIndex)) {
return HINT_NOT_PURCHASABLE_ALREADY_PURCHASED;
}
if (areDependenciesMissing(subProductIndex)) {
return HINT_NOT_PURCHASABLE_DEPENDENCIES_MISSING;
}
return mPurse.getCurrentScore() >= mCosts[subProductIndex] ? HINT_PURCHASABLE : HINT_NOT_PURCHASABLE_TOO_EXPENSIVE;
}
@Override
public int getSpentScore(int subProductIndex) {
int spent = 0;
for (int i = 0; i < mCosts.length; i++) {
if (isPurchased(i) && (subProductIndex == GENERAL_PRODUCT_INDEX || subProductIndex == i)) {
spent += mCosts[i];
}
}
return spent;
}
@Override
public CharSequence getCostText(Resources resources, int subProductIndex) {
int cost = mCosts[subProductIndex];
if (cost > 0) {
return String.valueOf(cost);
} else {
return resources.getString(R.string.shop_article_free);
}
}
@Override
public int getSubProductCount() {
return getMaxPurchaseCount();
}
@Override
public SubProduct getSubProduct(LayoutInflater inflater, int subProductIndex) {
// ensure multi product exists
MultiProduct product = mProducts[subProductIndex];
if (product == null) {
product = new MultiProduct(inflater, subProductIndex);
mProducts[subProductIndex] = product;
}
if (!isPurchased(subProductIndex)) {
// not yet purchased, add confirm product view
ConfirmProduct confirm = product.mConfirm;
if (confirm == null) {
confirm = new ConfirmProduct(this);
confirm.inflateView(inflater);
}
CharSequence costText;
CharSequence depText;
int cost = mCosts[subProductIndex];
if (confirm.hasNoView()) {
costText = String.valueOf(cost);
depText = "---";
} else {
Resources res = confirm.getView().getResources();
costText = getCostText(res, subProductIndex);
depText = makeMissingDependenciesText(res, subProductIndex);
}
int purchasable = isPurchasable(subProductIndex);
confirm.setConfirmable(purchasable, costText, depText, cost > 0 && (purchasable == HINT_PURCHASABLE || purchasable == HINT_NOT_PURCHASABLE_TOO_EXPENSIVE) ? R.drawable.think_currency_small : 0);
product.addConfirmView(confirm);
} else {
product.removeConfirmView();
}
return product;
}
@Override
public void onChildClick(SubProduct product) {
int index = -1;
for (int i = 0; i < mProducts.length; i++) {
if (mProducts[i] == product) {
index = i;
break;
}
}
if (index < 0) {
return;
}
int newShopValue = mPurse.getShopValue(mKey);
newShopValue |= (1 << index);
if (isPurchasable(index) == HINT_PURCHASABLE && mPurse.purchaseHigherValue(mKey, mCosts[index], newShopValue) && mListener != null) {
mListener.onArticleChanged(this);
}
}
@Override
public int getPurchaseProgressPercent() {
return (int) (100 * getPurchasedCount() / (double) getMaxPurchaseCount());
}
private class MultiProduct extends SubProduct {
private ViewGroup mViewGroup;
private String mDescr;
private ConfirmProduct mConfirm;
public MultiProduct(LayoutInflater inflater, int subProductIndex) {
super(R.layout.shop_article_multi_product);
setParentArticle(ShopArticleMulti.this);
String[] descrs = inflater.getContext().getResources().getStringArray(mProductDescrResId);
if (descrs.length > 0 && descrs.length > subProductIndex) {
mDescr = descrs[subProductIndex];
} else {
mDescr = "";
}
inflateView(inflater);
}
@Override
public void inflateView(LayoutInflater inflater) {
super.inflateView(inflater);
mViewGroup = (ViewGroup) mView;
((TextView) mView.findViewById(R.id.product_descr)).setText(mDescr);
}
public void addConfirmView(ConfirmProduct confirm) {
mConfirm = confirm;
if (mViewGroup.getChildCount() == 1) {
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
layoutParams.gravity = Gravity.CENTER_HORIZONTAL;
mViewGroup.addView(confirm.getView());
}
}
public void removeConfirmView() {
mConfirm = null;
if (mViewGroup.getChildCount() > 1) {
mViewGroup.removeViewAt(mViewGroup.getChildCount() - 1);
}
}
}
}