package fr.openwide.core.wicket.more.markup.html.template.js.jquery.plugins.datepickersync;
import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import org.apache.wicket.Component;
import org.apache.wicket.model.IDetachable;
import org.apache.wicket.model.IModel;
import org.apache.wicket.util.lang.Args;
import org.wicketstuff.wiquery.core.javascript.ChainableStatement;
import org.wicketstuff.wiquery.core.javascript.JsStatement;
import org.wicketstuff.wiquery.core.options.Options;
import org.wicketstuff.wiquery.ui.datepicker.DateOption;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
import fr.openwide.core.commons.util.CloneUtils;
import fr.openwide.core.wicket.more.markup.html.form.DatePicker;
public class DatePickerSync implements ChainableStatement, IDetachable, Serializable {
private static final long serialVersionUID = 5661268666461455313L;
private static final String DATE_PICKER_SYNC = "datePickerSync";
private static final String JS_ARRAY_START = "[";
private static final String JS_ARRAY_CLOSE = "]";
@Deprecated
private final DatePicker courant;
private final List<DatePicker> precedents = Lists.newArrayList();
private final List<IModel<? extends Date>> precedentsModels = Lists.newArrayList();
private final List<DatePicker> suivants = Lists.newArrayList();
private final List<IModel<? extends Date>> suivantsModels = Lists.newArrayList();
private final DatePickerSyncActionOnUpdate actionOnUpdate;
public DatePickerSync() {
this.courant = null;
this.actionOnUpdate = DatePickerSyncActionOnUpdate.NOTHING;
}
/**
* @deprecated Use {@link #DatePickerSync(DatePicker, DatePicker, DatePickerSyncActionOnUpdate)} instead with
* {@link DatePickerSyncActionOnUpdate#NOTHING}
* @param courant
*/
public DatePickerSync(DatePicker precedent, DatePicker suivant) {
this(precedent, suivant, DatePickerSyncActionOnUpdate.NOTHING);
}
public DatePickerSync(DatePicker precedent, DatePicker suivant, DatePickerSyncActionOnUpdate actionOnUpdate) {
this.courant = null;
if (precedent != null) {
addPrecedents(precedent);
}
if (suivant != null) {
addSuivants(suivant);
}
this.actionOnUpdate = actionOnUpdate;
}
/**
* @deprecated Use {@link #DatePickerSync()} instead.
* @param courant
*/
@Deprecated
public DatePickerSync(DatePicker courant) {
this(courant, (DatePicker) null, (DatePicker) null);
}
/**
* @deprecated Use {@link #DatePickerSync(DatePicker, DatePicker, DatePickerSyncActionOnUpdateS)} instead with
* {@link DatePickerSyncActionOnUpdate#NOTHING}
* @param courant
*/
public DatePickerSync(DatePicker courant, DatePicker precedent, DatePicker suivant) {
super();
Args.notNull(courant, "courant");
this.courant = courant;
if (precedent != null) {
addPrecedents(precedent);
}
if (suivant != null) {
addSuivants(suivant);
}
this.actionOnUpdate = DatePickerSyncActionOnUpdate.NOTHING;
}
@Override
public String chainLabel() {
return DATE_PICKER_SYNC;
}
@Override
public CharSequence[] statementArgs() {
Options options = new Options();
if (!precedents.isEmpty()) {
options.put("precedents", componentsToJSArray(precedents));
}
Collection<Date> precedentsModelsDates = getDates(precedentsModels);
if (!precedentsModelsDates.isEmpty()) {
options.put("precedentsModelsMaxDate", new DateOption(Ordering.<Date>natural().max(precedentsModelsDates)));
}
if (!suivants.isEmpty()) {
options.put("suivants", componentsToJSArray(suivants));
}
Collection<Date> suivantsModelsDates = getDates(suivantsModels);
if (!suivantsModelsDates.isEmpty()) {
options.put("suivantsModelsMinDate", new DateOption(Ordering.<Date>natural().min(suivantsModelsDates)));
}
if (actionOnUpdate != null) {
options.putLiteral("actionOnUpdate", actionOnUpdate.name());
} else {
options.putLiteral("actionOnUpdate", DatePickerSyncActionOnUpdate.NOTHING.name());
}
return new CharSequence[] { options.getJavaScriptOptions() };
}
public List<DatePicker> getPrecedents() {
return CloneUtils.clone(precedents);
}
public DatePickerSync addPrecedents(DatePicker first, DatePicker ... rest) {
for (DatePicker precedent : Lists.asList(first, rest)) {
if (precedent != null) {
if (precedent.equals(courant)) {
throw new IllegalArgumentException("Le date picker courant ne peut pas être ajouté en tant que précédent.");
}
if (!this.precedents.contains(precedent)) {
this.precedents.add(precedent);
}
}
}
return this;
}
public List<IModel<? extends Date>> getPrecedentsModels() {
return CloneUtils.clone(precedentsModels);
}
@SafeVarargs
public final DatePickerSync addPrecedentsModels(IModel<? extends Date> first, IModel<? extends Date> ... rest) {
for (IModel<? extends Date> precedent : Lists.asList(first, rest)) {
if (precedent != null) {
if (!this.precedentsModels.contains(precedent)) {
this.precedentsModels.add(precedent);
}
}
}
return this;
}
public List<DatePicker> getSuivants() {
return CloneUtils.clone(suivants);
}
public DatePickerSync addSuivants(DatePicker first, DatePicker ... rest) {
for (DatePicker suivant : Lists.asList(first, rest)) {
if (suivant != null) {
if (suivant.equals(courant)) {
throw new IllegalArgumentException("Le date picker courant ne peut pas être ajouté en tant que suivant.");
}
if (!this.suivants.contains(suivant)) {
this.suivants.add(suivant);
}
}
}
return this;
}
public List<IModel<? extends Date>> getSuivantsModels() {
return CloneUtils.clone(suivantsModels);
}
@SafeVarargs
public final DatePickerSync addSuivantsModels(IModel<? extends Date> first, IModel<? extends Date> ... rest) {
for (IModel<? extends Date> suivant : Lists.asList(first, rest)) {
if (suivant != null) {
if (!this.suivantsModels.contains(suivant)) {
this.suivantsModels.add(suivant);
}
}
}
return this;
}
private static String componentsToJSArray(Collection<? extends Component> components) {
StringBuilder componentsSb = new StringBuilder(JS_ARRAY_START);
for (Component component : components) {
if (componentsSb.length() > JS_ARRAY_START.length()) {
componentsSb.append(", ");
}
componentsSb.append(new JsStatement().$(component).render(false).toString());
}
componentsSb.append(JS_ARRAY_CLOSE);
return componentsSb.toString();
}
private static Collection<Date> getDates(Collection<? extends IModel<? extends Date>> models) {
List<Date> result = Lists.newArrayList();
for (IModel<? extends Date> model : models) {
Date date = model.getObject();
if (date != null) {
result.add(date);
}
}
return result;
}
@Override
public void detach() {
for (IModel<?> model : precedentsModels) {
model.detach();
}
for (IModel<?> model : suivantsModels) {
model.detach();
}
}
}