/* (non-Javadoc)
   * @see org.bedework.synch.cnctrs.ConnectorInstance#fetchItem(java.lang.String)
   */
  @Override
  public FetchItemResponseType fetchItem(final String uid) throws SynchException {
    getIcal();

    if (sub.changed()) {
      cnctr.getSyncher().updateSubscription(sub);
    }

    MapEntry me = uidMap.get(uid);

    FetchItemResponseType fir = new FetchItemResponseType();

    if (me == null) {
      fir.setStatus(StatusType.NOT_FOUND);
      return fir;
    }

    fir.setHref(info.getUri() + "#" + uid);
    fir.setChangeToken(info.getChangeToken());

    IcalendarType ical = new IcalendarType();
    VcalendarType vcal = new VcalendarType();

    ical.getVcalendar().add(vcal);

    vcal.setProperties(new ArrayOfProperties());
    List<JAXBElement<? extends BasePropertyType>> pl = vcal.getProperties().getBasePropertyOrTzid();

    ProdidPropType prod = new ProdidPropType();
    prod.setText(prodid);
    pl.add(of.createProdid(prod));

    VersionPropType vers = new VersionPropType();
    vers.setText("2.0");
    pl.add(of.createVersion(vers));

    ArrayOfComponents aoc = new ArrayOfComponents();
    vcal.setComponents(aoc);

    aoc.getBaseComponent().addAll(me.comps);
    fir.setIcalendar(ical);

    return fir;
  }
  /* Fetch the iCalendar for the subscription. If it fails set the status and
   * return null. Unchanged data will return null with no status change.
   */
  private void getIcal() throws SynchException {
    try {
      if (fetchedIcal != null) {
        return;
      }

      getClient();

      Header[] hdrs = null;

      if ((uidMap != null) && (info.getChangeToken() != null) && (fetchedIcal != null)) {
        hdrs = new Header[] {new BasicHeader("If-None-Match", info.getChangeToken())};
      }

      int rc = client.sendRequest("GET", info.getUri(), hdrs);
      info.setLastRefreshStatus(String.valueOf(rc));

      if (rc == HttpServletResponse.SC_NOT_MODIFIED) {
        // Data unchanged.
        if (debug) {
          trace("data unchanged");
        }
        return;
      }

      if (rc != HttpServletResponse.SC_OK) {
        info.setLastRefreshStatus(String.valueOf(rc));
        if (debug) {
          trace("Unsuccessful response from server was " + rc);
        }
        info.setChangeToken(null); // Force refresh next time
        return;
      }

      CalendarBuilder builder = new CalendarBuilder();

      InputStream is = client.getResponse().getContentStream();

      Calendar ical = builder.build(is);

      /* Convert each entity to XML */

      fetchedIcal = IcalToXcal.fromIcal(ical, null);

      uidMap = new HashMap<String, MapEntry>();

      prodid = null;

      for (VcalendarType vcal : fetchedIcal.getVcalendar()) {
        /* Extract the prodid from the converted calendar - we use it when we
         * generate a new icalendar for each entity.
         */
        if ((prodid == null) && (vcal.getProperties() != null)) {
          for (JAXBElement<? extends BasePropertyType> pel :
              vcal.getProperties().getBasePropertyOrTzid()) {
            if (pel.getValue() instanceof ProdidPropType) {
              prodid = ((ProdidPropType) pel.getValue()).getText();
              break;
            }
          }
        }

        for (JAXBElement<? extends BaseComponentType> comp :
            vcal.getComponents().getBaseComponent()) {
          UidPropType uidProp = (UidPropType) XcalUtil.findProperty(comp.getValue(), XcalTags.uid);

          if (uidProp == null) {
            // Should flag as an error
            continue;
          }

          String uid = uidProp.getText();

          MapEntry me = uidMap.get(uid);

          if (me == null) {
            me = new MapEntry();
            me.uid = uid;
            uidMap.put(uidProp.getText(), me);
          }

          LastModifiedPropType lm =
              (LastModifiedPropType) XcalUtil.findProperty(comp.getValue(), XcalTags.lastModified);

          String lastmod = null;
          if (lm != null) {
            lastmod = lm.getUtcDateTime().toXMLFormat();
          }

          if (Util.cmpObjval(me.lastMod, lastmod) < 0) {
            me.lastMod = lastmod;
          }

          me.comps.add(comp);
        }
      }

      /* Looks like we translated ok. Save any etag and delete everything in the
       * calendar.
       */

      String etag = client.getResponse().getResponseHeaderValue("Etag");
      if (etag != null) {
        info.setChangeToken(etag);
      }
    } catch (SynchException se) {
      throw se;
    } catch (Throwable t) {
      throw new SynchException(t);
    } finally {
      try {
        client.release();
      } catch (Throwable t) {
      }
    }
  }