public void setAll(String json) {
    albums = new HashMap<String, JSONObject>();
    images = new HashMap<String, Map<String, JSONObject>>();

    try {
      JSONArray jAlbums = new JSONArray(json);

      String albumId;
      JSONObject jo;

      for (int i = 0; i < jAlbums.length(); i++) {
        jo = jAlbums.getJSONObject(i);

        if (!jo.has("id")) {
          error.fire(new ErrorEvent("Error, object does not contain albums"));
        }

        albumId = jo.getString("id");

        images.put(albumId, new HashMap<String, JSONObject>());
        if (jo.getInt("size") > 0) {
          storeImagesToAlbum(albumId, jo.getJSONArray("images"));
          jo.remove("images");
        }
        albums.put(albumId, jo);
      }
      loaded = true;
      emptyCache = jAlbums.length() == 0;
    } catch (JSONException e) {
      error.fire(new ErrorEvent("Error: ", e.getMessage()));
    }
  }
  public void storeImagesToAlbum(String albumId, JSONArray ja) {
    String imageId = "";
    JSONObject jo;
    Map<String, JSONObject> album = images.get(albumId);

    try {
      for (int i = 0; i < ja.length(); i++) {
        jo = ja.getJSONObject(i);

        if (!jo.has("id")) {
          error.fire(new ErrorEvent("Error, object does not contain images"));
        }

        imageId = jo.getString("id");

        album.put(imageId, jo);
      }
    } catch (JSONException je) {
      error.fire(new ErrorEvent("Error", je.getMessage()));
    }
  }
    @Override
    public VisitResult visit(VisitContext context, UIComponent target) {

      if (target instanceof AbstractLegend) {
        copyAttrs(target, chart, "", asList("position", "sorting"));
      } else if (target instanceof AbstractSeries) {
        AbstractSeries s = (AbstractSeries) target;
        ChartDataModel model = s.getData();
        particularSeriesListeners.add(s.getPlotClickListener());

        // Collect Series specific handlers
        Map<String, Object> optMap = new HashMap<String, Object>();
        RenderKitUtils.Attributes seriesEvents =
            attributes()
                .generic("onplothover", "onplothover", "plothover")
                .generic("onplotclick", "onplotclick", "plotclick");

        addToScriptHash(
            optMap,
            context.getFacesContext(),
            target,
            seriesEvents,
            RenderKitUtils.ScriptHashVariableWrapper.eventHandler);

        if (optMap.get("onplotclick") != null) {
          plotClickHandlers.put(new RawJSONString(optMap.get("onplotclick").toString()));
        } else {
          plotClickHandlers.put(s.getOnplotclick());
        }

        if (optMap.get("onplothover") != null) {
          plothoverHandlers.put(new RawJSONString(optMap.get("onplothover").toString()));
        } else {
          plothoverHandlers.put(s.getOnplothover());
        }
        // end collect series specific handler

        if (model == null) {
          /**
           * data model priority: if there is data model passed through data attribute use it.
           * Otherwise nested point tags are expected.
           */
          VisitSeries seriesCallback = new VisitSeries(s.getType());
          s.visitTree(
              VisitContext.createVisitContext(FacesContext.getCurrentInstance()), seriesCallback);
          model = seriesCallback.getModel();

          // if series has no data create empty model
          if (model == null) {
            switch (s.getType()) {
              case line:
                model = new NumberChartDataModel(ChartType.line);
                break;
              case bar:
                model = new NumberChartDataModel(ChartType.bar);
                break;
              case pie:
                model = new StringChartDataModel(ChartType.pie);
                break;
              default:
                break;
            }
          } else {
            nodata = false;
          }
        } else {
          nodata = false;
        }
        model.setAttributes(s.getAttributes());

        try {
          // Check model/series compatibility

          if (chartType == null && (!nodata)) {
            // if series is empty do not set types
            chartType = model.getType();
            keyType = model.getKeyType();
            valType = model.getValueType();
          } else {
            if (chartType == ChartDataModel.ChartType.pie) {
              throw new IllegalArgumentException("Pie chart supports only one series.");
            }
          }
          if (keyType != model.getKeyType() || valType != model.getValueType()) {
            throw new IllegalArgumentException("Data model is not valid for this chart type.");
          }

          data.put(model.export());
        } catch (IOException ex) {
          throw new FacesException(ex);
        }

      } else if (target instanceof AbstractXAxis) {
        copyAttrs(target, chart, "x", asList("min", "max", "pad", "label", "format"));
      } else if (target instanceof AbstractYAxis) {
        copyAttrs(target, chart, "y", asList("min", "max", "pad", "label", "format"));
      }
      return VisitResult.ACCEPT;
    }