package org.sigmah.shared.dto.element;
/*
* #%L
* Sigmah
* %%
* Copyright (C) 2010 - 2016 URD
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Image;
import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.Component;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.sigmah.client.dispatch.CommandResultHandler;
import org.sigmah.client.dispatch.DispatchQueue;
import org.sigmah.client.dispatch.monitor.LoadingMask;
import org.sigmah.client.i18n.I18N;
import org.sigmah.client.page.Page;
import org.sigmah.client.page.RequestParameter;
import org.sigmah.client.ui.widget.HistoryTokenText;
import org.sigmah.client.ui.widget.contact.DedupeContactDialog;
import org.sigmah.client.ui.widget.form.ContactListComboBox;
import org.sigmah.client.ui.widget.form.Forms;
import org.sigmah.client.ui.widget.form.ListComboBox;
import org.sigmah.offline.sync.SuccessCallback;
import org.sigmah.shared.command.CheckContactDuplication;
import org.sigmah.shared.command.CreateEntity;
import org.sigmah.shared.command.DedupeContact;
import org.sigmah.shared.command.GetContactDuplicatedProperties;
import org.sigmah.shared.command.GetContacts;
import org.sigmah.shared.command.result.ContactDuplicatedProperty;
import org.sigmah.shared.command.result.CreateResult;
import org.sigmah.shared.command.result.ListResult;
import org.sigmah.shared.command.result.ValueResult;
import org.sigmah.shared.dto.ContactDTO;
import org.sigmah.shared.dto.ContactModelDTO;
import org.sigmah.shared.dto.element.event.ValueEvent;
import org.sigmah.shared.dto.history.HistoryTokenDTO;
import org.sigmah.shared.dto.history.HistoryTokenListDTO;
import org.sigmah.shared.dto.orgunit.OrgUnitDTO;
import org.sigmah.shared.dto.referential.ContactModelType;
import org.sigmah.shared.dto.referential.ValueEventChangeType;
import org.sigmah.shared.util.ValueResultUtils;
import com.allen_sauer.gwt.log.client.Log;
public class ContactListElementDTO extends FlexibleElementDTO {
private static final long serialVersionUID = 646913359144175456L;
public static final String ENTITY_NAME = "element.ContactListElement";
public static final String ALLOWED_TYPE = "allowedType";
public static final String ALLOWED_MODEL_IDS = "allowedModels";
public static final String LIMIT = "limit";
public static final String IS_MEMBER = "isMember";
@Override
@SuppressWarnings("unchecked")
protected Component getComponent(final ValueResult valueResult, final boolean enabled) {
final ContactListComboBox listComboBox = new ContactListComboBox(getLimit(), getAllowedType(), getAllowedModelIds(), dispatch);
listComboBox.setEnabled(enabled);
listComboBox.setChangeHandler(new ContactListComboBox.ChangeHandler() {
@Override
public void handleChange(List<ContactDTO> contacts, ValueEventChangeType changeType) {
fireEvents(serializeValue(contacts), changeType);
}
});
listComboBox.setCreateContactHandler(new ContactListComboBox.CreateContactHandler() {
@Override
public void handleContactCreation(final ContactModelDTO contactModelDTO, final String email, final String firstName, final String familyName, final String organizationName, final OrgUnitDTO mainOrgUnit, final List<OrgUnitDTO> secondaryOrgUnits) {
CheckContactDuplication checkContactDuplication;
if (contactModelDTO.getType() == ContactModelType.INDIVIDUAL) {
checkContactDuplication = new CheckContactDuplication(null, email, familyName, firstName, contactModelDTO);
} else {
checkContactDuplication = new CheckContactDuplication(null, email, familyName, null, contactModelDTO);
}
dispatch.execute(checkContactDuplication, new AsyncCallback<ListResult<ContactDTO>>() {
@Override
public void onFailure(Throwable caught) {
Log.error("Error while checking contact duplicates.");
}
@Override
public void onSuccess(ListResult<ContactDTO> result) {
final HashMap<String, Object> properties = buildPropertyMap(contactModelDTO, email, firstName, familyName, organizationName, mainOrgUnit, secondaryOrgUnits);
if (result == null || result.getSize() == 0) {
createEntity(properties, listComboBox);
return;
}
final DedupeContactDialog dedupeContactDialog = new DedupeContactDialog(true);
dedupeContactDialog.getPossibleDuplicatesGrid().getStore().add(result.getList());
dedupeContactDialog.getFirstStepMainButton().addSelectionListener(new SelectionListener<ButtonEvent>() {
@Override
public void componentSelected(ButtonEvent ce) {
createEntity(properties, listComboBox);
dedupeContactDialog.hide();
}
});
dedupeContactDialog.setSecondStepHandler(new DedupeContactDialog.SecondStepHandler() {
@Override
public void initialize(final Integer contactId, final ListStore<ContactDuplicatedProperty> propertiesStore) {
dispatch.execute(new GetContactDuplicatedProperties(contactId, null, properties), new CommandResultHandler<ListResult<ContactDuplicatedProperty>>() {
@Override
protected void onCommandSuccess(ListResult<ContactDuplicatedProperty> result) {
propertiesStore.add(result.getList());
}
}, new LoadingMask(dedupeContactDialog));
}
@Override
public void downloadImage(String id, final Image image) {
imageProvider.provideDataUrl(id, new SuccessCallback<String>() {
@Override
public void onSuccess(String dataUrl) {
image.setUrl(dataUrl);
}
});
}
@Override
public void handleDedupeContact(final Integer targetedContactId, List<ContactDuplicatedProperty> selectedProperties) {
dispatch.execute(new DedupeContact(selectedProperties, targetedContactId), new CommandResultHandler<ContactDTO>() {
@Override
protected void onCommandSuccess(ContactDTO targetedContactDTO) {
dedupeContactDialog.hide();
listComboBox.getListStore().add(targetedContactDTO);
}
});
}
@Override
public void handleCancel() {
dedupeContactDialog.hide();
}
});
dedupeContactDialog.show();
}
});
}
});
listComboBox.initComponent();
// TODO: Filter contacts following user choice
dispatch.execute(new GetContacts(getAllowedType(), getAllowedModelIds()), new AsyncCallback<ListResult<ContactDTO>>() {
@Override
public void onFailure(Throwable caught) {
Log.error("Error while trying to get contacts for a contact list element.", caught);
}
@Override
public void onSuccess(ListResult<ContactDTO> result) {
listComboBox.getAvailableValuesStore().add(result.getList());
Set<Integer> contactIds = parseValue(valueResult);
List<ContactDTO> contacts = new ArrayList<ContactDTO>();
for (ContactDTO contactDTO : result.getList()) {
if (contactIds.contains(contactDTO.getId())) {
contacts.add(contactDTO);
}
}
listComboBox.initListStore(contacts);
}
});
return Forms.adapter(getLabel(), listComboBox);
}
@Override
public boolean isCorrectRequiredValue(ValueResult result) {
return !parseValue(result).isEmpty();
}
public ContactModelType getAllowedType() {
return get(ALLOWED_TYPE);
}
public void setAllowedType(ContactModelType allowedType) {
set(ALLOWED_TYPE, allowedType);
}
public Set<Integer> getAllowedModelIds() {
return get(ALLOWED_MODEL_IDS);
}
public void setAllowedModelIds(Set<Integer> allowedModels) {
set(ALLOWED_MODEL_IDS, allowedModels);
}
public int getLimit() {
return get(LIMIT);
}
public void setLimit(int limit) {
set(LIMIT, limit);
}
public boolean isMember() {
return get(IS_MEMBER);
}
public void setMember(boolean isMember) {
set(IS_MEMBER, isMember);
}
@Override
public String getEntityName() {
return ENTITY_NAME;
}
public static Set<Integer> parseValue(ValueResult result) {
if (result == null || result.getValueObject() == null) {
return Collections.emptySet();
}
Set<Integer> ids = new HashSet<Integer>();
for (String serializedId : result.getValueObject().split(ValueResultUtils.DEFAULT_VALUE_SEPARATOR)) {
ids.add(Integer.parseInt(serializedId));
}
return ids;
}
private static Set<Integer> serializeValue(List<ContactDTO> contacts) {
Set<Integer> ids = new HashSet<Integer>();
for (ContactDTO contact : contacts) {
ids.add(contact.getId());
}
return ids;
}
private void createEntity(HashMap<String, Object> properties, final ListComboBox<ContactDTO> listComboBox) {
dispatch.execute(new CreateEntity(ContactDTO.ENTITY_NAME, properties), new AsyncCallback<CreateResult>() {
@Override
public void onFailure(Throwable caught) {
Log.error("Error while creating a new Contact from contact creation dialog.");
}
@Override
public void onSuccess(CreateResult result) {
listComboBox.getListStore().add((ContactDTO) result.getEntity());
}
});
}
private HashMap<String, Object> buildPropertyMap(ContactModelDTO contactModelDTO, String email, String firstName, String familyName, String organizationName, OrgUnitDTO mainOrgUnit, List<OrgUnitDTO> secondaryOrgUnits) {
HashMap<String, Object> properties = new HashMap<String, Object>();
properties.put(ContactDTO.CONTACT_MODEL, contactModelDTO.getId());
properties.put(ContactDTO.EMAIL, email);
properties.put(ContactDTO.FIRSTNAME, contactModelDTO.getType() == ContactModelType.INDIVIDUAL ? firstName : null);
properties.put(ContactDTO.NAME, contactModelDTO.getType() == ContactModelType.INDIVIDUAL ? familyName : organizationName);
if (mainOrgUnit != null) {
properties.put(ContactDTO.MAIN_ORG_UNIT, mainOrgUnit.getId());
}
if (secondaryOrgUnits != null) {
HashSet<Integer> secondaryOrgUnitIds = new HashSet<Integer>();
for (OrgUnitDTO secondaryOrgUnit : secondaryOrgUnits) {
secondaryOrgUnitIds.add(secondaryOrgUnit.getId());
}
properties.put(ContactDTO.SECONDARY_ORG_UNITS, secondaryOrgUnitIds);
}
return properties;
}
@Override
public Object renderHistoryToken(HistoryTokenListDTO historyTokenListDTO) {
final List<String> formattedTokens = new ArrayList<String>();
final HistoryTokenText historyTokenText = new HistoryTokenText();
DispatchQueue dispatchQueue = new DispatchQueue(dispatch);
for (final HistoryTokenDTO historyTokenDTO : historyTokenListDTO.getTokens()) {
// Contact list element value in a HistoryToken is always monovalued and combined to a ADD or REMOVED action
dispatchQueue.add(new GetContacts(new HashSet<Integer>(ValueResultUtils.splitValuesAsInteger(historyTokenDTO.getValue()))), new CommandResultHandler<ListResult<ContactDTO>>() {
@Override
protected void onCommandSuccess(ListResult<ContactDTO> result) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < result.getList().size(); i++) {
if (i != 0) {
stringBuilder.append(", ");
}
stringBuilder.append(result.getList().get(i).getFullName());
}
switch (historyTokenDTO.getType()) {
case ADD:
formattedTokens.add(I18N.MESSAGES.contactListHistoryAdded(stringBuilder.toString()));
break;
case REMOVE:
formattedTokens.add(I18N.MESSAGES.contactListHistoryRemoved(stringBuilder.toString()));
break;
case EDIT:
formattedTokens.add(stringBuilder.toString());
break;
default:
throw new IllegalStateException("Unknown ValueEventChangeType : " + historyTokenDTO.getType());
}
historyTokenText.setHistoryTokenValue(formattedTokens);
}
});
}
dispatchQueue.start();
return historyTokenText;
}
private void fireEvents(Set<Integer> value, ValueEventChangeType changeType) {
handlerManager.fireEvent(new ValueEvent(ContactListElementDTO.this, value, changeType));
}
}