gt:       final AddressDO address = entry.getAddress();
context: /////////////////////////////////////////////////////////////////////////////
  //
  // Project ProjectForge Community Edition
  //         www.projectforge.org
  //
  // Copyright (C) 2001-2013 Kai Reinhard (k.reinhard@micromata.de)
  //
  // ProjectForge is dual-licensed.
  //
  // This community edition 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; version 3 of the License.
  //
  // This community edition 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/.
  //
  /////////////////////////////////////////////////////////////////////////////
  
  package org.projectforge.address;
  
  import java.io.PrintWriter;
  import java.io.Writer;
  import java.text.DateFormat;
  import java.text.SimpleDateFormat;
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.Date;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Locale;
  import java.util.Set;
  import java.util.TreeSet;
  
  import org.apache.commons.collections.CollectionUtils;
  import org.apache.commons.lang.StringUtils;
  import org.apache.commons.lang.Validate;
  import org.hibernate.criterion.Order;
  import org.hibernate.criterion.Restrictions;
  import org.projectforge.access.AccessType;
  import org.projectforge.access.OperationType;
  import org.projectforge.common.DateHelper;
  import org.projectforge.common.DateHolder;
  import org.projectforge.common.NumberHelper;
  import org.projectforge.core.BaseDao;
  import org.projectforge.core.BaseSearchFilter;
  import org.projectforge.core.Configuration;
  import org.projectforge.core.ConfigurationParam;
  import org.projectforge.core.QueryFilter;
  import org.projectforge.task.TaskDO;
  import org.projectforge.task.TaskDao;
  import org.projectforge.user.PFUserDO;
  
  /**
   * 
   * @author Kai Reinhard (k.reinhard@micromata.de)
   * 
   */
  public class AddressDao extends BaseDao<AddressDO>
  {
    private static final DateFormat V_CARD_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
  
    private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(AddressDao.class);
  
    private Configuration configuration;
  
    private TaskDao taskDao;
  
    public void setConfiguration(final Configuration configuration)
    {
      this.configuration = configuration;
    }
  
    public void setTaskDao(final TaskDao taskDao)
    {
      this.taskDao = taskDao;
    }
  
    private PersonalAddressDao personalAddressDao;
  
    public void setPersonalAddressDao(final PersonalAddressDao personalAddressDao)
    {
      this.personalAddressDao = personalAddressDao;
    }
  
    public AddressDao()
    {
      super(AddressDO.class);
    }
  
    /**
     * Addresses will be assigned to a default task.
     */
    public Integer getDefaultTaskId()
    {
      return configuration.getTaskIdValue(ConfigurationParam.DEFAULT_TASK_ID_4_ADDRESSES);
    }
  
    public List<Locale> getUsedCommunicationLanguages()
    {
      @SuppressWarnings("unchecked")
      final List<Locale> list = getHibernateTemplate()
      .find(
          "select distinct a.communicationLanguage from AddressDO a where deleted=false and a.communicationLanguage is not null order by a.communicationLanguage");
      return list;
    }
  
    /**
     * Get the newest address entries (by time of creation).
     * @return
     * @see #getNewestMax()
     */
    public List<AddressDO> getNewest(final BaseSearchFilter filter)
    {
      final QueryFilter queryFilter = new QueryFilter();
      queryFilter.addOrder(Order.desc("created"));
      if (filter.getMaxRows() > 0) {
        queryFilter.setMaxResults(filter.getMaxRows());
      }
      return getList(queryFilter);
    }
  
    @Override
    public List<AddressDO> getList(final BaseSearchFilter filter)
    {
      final AddressFilter myFilter;
      if (filter instanceof AddressFilter) {
        myFilter = (AddressFilter) filter;
      } else {
        myFilter = new AddressFilter(filter);
      }
      final QueryFilter queryFilter = new QueryFilter(myFilter);
      if (StringUtils.isBlank(myFilter.getSearchString()) == true) {
        if (myFilter.isDeleted() == false) {
          if (myFilter.isNewest() == true) {
            return getNewest(myFilter);
          }
          if (myFilter.isMyFavorites() == true) {
            // Show only favorites.
            return personalAddressDao.getMyAddresses();
          }
        }
      } else {
        if (StringUtils.isNumeric(filter.getSearchString()) == true) {
          myFilter.setSearchString("*" + myFilter.getSearchString() + "*");
        }
      }
      if ("filter".equals(myFilter.getListType()) == true) {
        // Proceed contact status:
        // Use filter only for non deleted entries:
        if (myFilter.isActive() == true
            || myFilter.isNonActive() == true
            || myFilter.isUninteresting() == true
            || myFilter.isDeparted() == true
            || myFilter.isPersonaIngrata() == true) {
          final Collection<ContactStatus> col = new ArrayList<ContactStatus>();
          if (myFilter.isActive() == true) {
            col.add(ContactStatus.ACTIVE);
          }
          if (myFilter.isNonActive() == true) {
            col.add(ContactStatus.NON_ACTIVE);
          }
          if (myFilter.isUninteresting() == true) {
            col.add(ContactStatus.UNINTERESTING);
          }
          if (myFilter.isDeparted() == true) {
            col.add(ContactStatus.DEPARTED);
          }
          if (myFilter.isPersonaIngrata() == true) {
            col.add(ContactStatus.PERSONA_INGRATA);
          }
          queryFilter.add(Restrictions.in("contactStatus", col));
        }
  
        // Proceed address status:
        // Use filter only for non deleted books:
        if (myFilter.isUptodate() == true || myFilter.isOutdated() == true || myFilter.isLeaved() == true) {
          final Collection<AddressStatus> col = new ArrayList<AddressStatus>();
          if (myFilter.isUptodate() == true) {
            col.add(AddressStatus.UPTODATE);
          }
          if (myFilter.isOutdated() == true) {
            col.add(AddressStatus.OUTDATED);
          }
          if (myFilter.isLeaved() == true) {
            col.add(AddressStatus.LEAVED);
          }
          queryFilter.add(Restrictions.in("addressStatus", col));
        }
      }
      queryFilter.addOrder(Order.asc("name"));
      return getList(queryFilter);
    }
  
    /**
     * @param address
     * @param taskId If null, then task will be set to null;
     * @see BaseDao#getOrLoad(Integer)
     */
    public void setTask(final AddressDO address, final Integer taskId)
    {
      final TaskDO task = taskDao.getOrLoad(taskId);
      address.setTask(task);
    }
  
    /**
     * return Always true, no generic select access needed for address objects.
     * @see org.projectforge.core.BaseDao#hasSelectAccess()
     */
    @Override
    public boolean hasSelectAccess(final PFUserDO user, final boolean throwException)
    {
      return true;
    }
  
    private void beforeUpdateOrSave(final AddressDO address)
    {
      if (address != null && address.getTaskId() == null) {
        setTask(address, getDefaultTaskId());
      }
    }
  
    /**
     * @see org.projectforge.core.BaseDao#hasAccess(Object, OperationType)
     */
    @Override
    public boolean hasAccess(final PFUserDO user, final AddressDO obj, final AddressDO oldObj, final OperationType operationType,
        final boolean throwException)
    {
      beforeUpdateOrSave(obj);
      return accessChecker.hasPermission(user, obj.getTaskId(), AccessType.TASKS, operationType, throwException);
    }
  
    /**
     * @see org.projectforge.core.BaseDao#hasUpdateAccess(Object, Object)
     */
    @Override
    public boolean hasUpdateAccess(final PFUserDO user, final AddressDO obj, final AddressDO dbObj, final boolean throwException)
    {
      Validate.notNull(dbObj);
      Validate.notNull(obj);
      beforeUpdateOrSave(obj);
      Validate.notNull(dbObj.getTaskId());
      Validate.notNull(obj.getTaskId());
      if (accessChecker.hasPermission(user, obj.getTaskId(), AccessType.TASKS, OperationType.UPDATE, throwException) == false) {
        return false;
      }
      if (dbObj.getTaskId().equals(obj.getTaskId()) == false) {
        // User moves the object to another task:
        if (accessChecker.hasPermission(user, obj.getTaskId(), AccessType.TASKS, OperationType.INSERT, throwException) == false) {
          // Inserting of object under new task not allowed.
          return false;
        }
        if (accessChecker.hasPermission(user, dbObj.getTaskId(), AccessType.TASKS, OperationType.DELETE, throwException) == false) {
          // Deleting of object under old task not allowed.
          return false;
        }
      }
      return true;
    }
  
    /**
     * Get the birthdays of address entries.
     * @param fromDate Search for birthdays from given date (ignoring the year).
     * @param toDate Search for birthdays until given date (ignoring the year).
     * @param max Maximum number of result entries.
     * @param all If false, only the birthdays of favorites will be returned.
     * @return The entries are ordered by date of year and name.
     */
    public Set<BirthdayAddress> getBirthdays(final Date fromDate, final Date toDate, final int max, final boolean all)
    {
      final QueryFilter filter = new QueryFilter();
      filter.add(Restrictions.isNotNull("birthday"));
      final List<AddressDO> list = getList(filter);
      // Uses not Collections.sort because every comparison needs Calendar.getDayOfYear().
      final Set<BirthdayAddress> set = new TreeSet<BirthdayAddress>();
      final Set<Integer> favorites = getFavorites();
      final DateHolder from = new DateHolder(fromDate);
      final DateHolder to = new DateHolder(toDate);
      DateHolder dh;
      final int fromMonth = from.getMonth();
      final int fromDayOfMonth = from.getDayOfMonth();
      final int toMonth = to.getMonth();
      final int toDayOfMonth = to.getDayOfMonth();
      for (final AddressDO address : list) {
        if (all == false && favorites.contains(address.getId()) == false) {
          // Address is not a favorite address, so ignore it.
          continue;
        }
        dh = new DateHolder(address.getBirthday());
        final int month = dh.getMonth();
        final int dayOfMonth = dh.getDayOfMonth();
        if (DateHelper.dateOfYearBetween(month, dayOfMonth, fromMonth, fromDayOfMonth, toMonth, toDayOfMonth) == false) {
          continue;
        }
        final BirthdayAddress ba = new BirthdayAddress(address);
        if (favorites.contains(address.getId()) == true) {
          ba.setFavorite(true);
        }
        set.add(ba);
      }
      return set;
    }
  
    public List<PersonalAddressDO> getFavoriteVCards()
    {
      final List<PersonalAddressDO> list = personalAddressDao.getList();
      final List<PersonalAddressDO> result = new ArrayList<PersonalAddressDO>();
      if (CollectionUtils.isNotEmpty(list) == true) {
        for (final PersonalAddressDO entry : list) {
          if (entry.isFavoriteCard() == true) {
            result.add(entry);
          }
        }
      }
      return result;
    }
  
    public Set<Integer> getFavorites()
    {
      final List<PersonalAddressDO> list = personalAddressDao.getList();
      final Set<Integer> result = new HashSet<Integer>();
      if (CollectionUtils.isNotEmpty(list) == true) {
        for (final PersonalAddressDO entry : list) {
          if (entry.isFavoriteCard() == true) {
            result.add(entry.getAddressId());
          }
        }
      }
      return result;
    }
  
    public void exportFavoriteVCards(final Writer out, final List<PersonalAddressDO> favorites)
    {
      log.info("Exporting personal AddressBook.");
      final PrintWriter pw = new PrintWriter(out);
      for (final PersonalAddressDO entry : favorites) {
        if (entry.isFavoriteCard() == false) {
          // Entry is not marks as vCard-Entry.
          continue;
        }
        final AddressDO addressDO = entry.getAddress();
        exportVCard(pw, addressDO);
      }
      pw.flush();
    }
  
    /**
     * Exports a single vcard for the given addressDO
     * @param pw
     * @param addressDO
     * @return
     */
    public void exportVCard(final PrintWriter pw, final AddressDO addressDO)
    {
      if (log.isDebugEnabled() == true) {
        log.debug("Exporting vCard for addressDo : " + addressDO != null ? addressDO.getId() : null);
      }
      pw.println("BEGIN:VCARD");
      pw.println("VERSION:3.0");
      pw.print("N:");
      out(pw, addressDO.getName());
      pw.print(';');
      out(pw, addressDO.getFirstName());
      pw.print(";;");
      out(pw, addressDO.getTitle());
      pw.println(";");
      print(pw, "FN:", getFullName(addressDO));
      if (isGiven(addressDO.getOrganization()) == true || isGiven(addressDO.getDivision()) == true) {
        pw.print("ORG:");
        out(pw, addressDO.getOrganization());
        pw.print(';');
        if (isGiven(addressDO.getDivision()) == true) {
          out(pw, addressDO.getDivision());
        }
        pw.println();
      }
      print(pw, "TITLE:", addressDO.getPositionText());
      print(pw, "EMAIL;type=INTERNET;type=WORK;type=pref:", addressDO.getEmail());
      print(pw, "EMAIL;type=INTERNET;type=HOME;type=pref:", addressDO.getPrivateEmail());
      print(pw, "TEL;type=WORK;type=pref:", addressDO.getBusinessPhone());
      print(pw, "TEL;TYPE=CELL:", addressDO.getMobilePhone());
      print(pw, "TEL;type=WORK;type=FAX:", addressDO.getFax());
      print(pw, "TEL;TYPE=HOME:", addressDO.getPrivatePhone());
      print(pw, "TEL;TYPE=HOME;type=CELL:", addressDO.getPrivateMobilePhone());
  
      if (isGiven(addressDO.getAddressText()) == true || isGiven(addressDO.getCity()) == true || isGiven(addressDO.getZipCode()) == true) {
        pw.print("ADR;TYPE=WORK:;;");
        out(pw, addressDO.getAddressText());
        pw.print(';');
        out(pw, addressDO.getCity());
        pw.print(";;");
        out(pw, addressDO.getZipCode());
        pw.print(';');
        out(pw, addressDO.getCountry());
        pw.println();
      }
      if (isGiven(addressDO.getPrivateAddressText()) == true
          || isGiven(addressDO.getPrivateCity()) == true
          || isGiven(addressDO.getPrivateZipCode()) == true) {
        pw.print("ADR;TYPE=HOME:;;");
        out(pw, addressDO.getPrivateAddressText());
        pw.print(';');
        out(pw, addressDO.getPrivateCity());
        pw.print(";;");
        out(pw, addressDO.getPrivateZipCode());
        pw.print(";");
        pw.println();
      }
      print(pw, "URL;type=pref:", addressDO.getWebsite());
      if (addressDO.getBirthday() != null) {
        print(pw, "BDAY;value=date:", V_CARD_DATE_FORMAT.format(addressDO.getBirthday()));
      }
      if (isGiven(addressDO.getComment()) == true) {
        print(pw, "NOTE:", addressDO.getComment() + "\\nCLASS: WORK");
      } else {
        print(pw, "NOTE:", "CLASS: WORK");
      }
      // pw.println("TZ:+00:00");
      pw.println("CATEGORIES:ProjectForge");
      pw.print("UID:U");
      pw.println(addressDO.getId());
      pw.println("END:VCARD");
      pw.println();
      // Unused: addressDO.getState();
    }
  
    /**
     * Used by vCard export for field 'FN' (full name). Concatenates first name, last name and title.
     * @return
     */
    public String getFullName(final AddressDO a)
    {
      final StringBuffer buf = new StringBuffer();
      boolean space = false;
      if (isGiven(a.getName()) == true) {
        buf.append(a.getName());
        space = true;
      }
      if (isGiven(a.getFirstName()) == true) {
        if (space == true) {
          buf.append(' ');
        } else {
          space = true;
        }
        buf.append(a.getFirstName());
      }
      if (isGiven(a.getTitle()) == true) {
        if (space == true) {
          buf.append(' ');
        } else {
          space = true;
        }
        buf.append(a.getTitle());
      }
      return buf.toString();
    }
  
    public List<PersonalAddressDO> getFavoritePhoneEntries()
    {
      final List<PersonalAddressDO> list = personalAddressDao.getList();
      final List<PersonalAddressDO> result = new ArrayList<PersonalAddressDO>();
      if (CollectionUtils.isNotEmpty(list) == true) {
        for (final PersonalAddressDO entry : list) {
          if (entry.isFavoriteBusinessPhone() == true
              || entry.isFavoriteFax() == true
              || entry.isFavoriteMobilePhone() == true
              || entry.isFavoritePrivatePhone() == true) {
            result.add(entry);
          }
        }
      }
      return result;
    }
  
    /**
     * Throws UserException, if for example the phone list is empty.
     */
    public void exportFavoritePhoneList(final Writer out, final List<PersonalAddressDO> favorites)
    {
      log.info("Exporting phone list");
      final PrintWriter pw = new PrintWriter(out);
      pw.println("\"Name\",\"Phone number\"");
      for (final PersonalAddressDO entry : favorites) {
  