public class PublishingManagerImpl implements PublishingManager {

  private static final Logger LOGGER = LoggerFactory.getLogger(PublishingManagerImpl.class);

  private static final String TARGET_REQUEST_PARAMETER = "target";
  private static final String VERSION_REQUEST_PARAMETER = "version";
  private static final String PASSWORD_REQUEST_PARAMETER = "password";
  private static final String SITE_REQUEST_PARAMETER = "siteId";
  private static final String DELETED_FILES_REQUEST_PARAMETER = "deletedFiles";
  private static final String CONTENT_LOCATION_REQUEST_PARAMETER = "contentLocation";
  private static final String CONTENT_FILE_REQUEST_PARAMETER = "contentFile";
  private static final String METADATA_FILE_REQUEST_PARAMETER = "metadataFile";

  private static final String FILES_SEPARATOR = ",";
  private static final String LIVE_ENVIRONMENT = "live";
  private static final String PRODUCTION_ENVIRONMENT = "Production";
  private static final String WORK_AREA_ENVIRONMENT = "work-area";

  @Override
  public Set<String> getAllAvailableSites() {
    return _contentRepository.getAllAvailableSites();
  }

  @Override
  public Set<PublishingTargetItem> getAllTargetsForSite(String site) {
    return _contentRepository.getAllTargetsForSite(site);
  }

  @Override
  public boolean checkConnection(PublishingTargetItem target) {
    boolean connOk = false;
    if (target.getStatusUrl() != null && !target.getStatusUrl().isEmpty()) {
      LOGGER.debug(String.format("Check deployment agent status for target ", target.getName()));
      URL statusUrl = null;
      try {
        statusUrl = new URL(target.getStatusUrl());
      } catch (MalformedURLException e) {
        LOGGER.error(
            String.format(
                "Invalid endpoint status URL for publishing channel [%s]", target.getName()),
            e);
      }
      GetMethod getMethod = null;
      HttpClient client = null;
      try {
        getMethod = new GetMethod(target.getStatusUrl());
        client = new HttpClient();
        int status = client.executeMethod(getMethod);
        if (status == HttpStatus.SC_OK) {
          connOk = true;
        }

      } catch (Exception e) {
        LOGGER.error(
            String.format(
                "Target (%s) is not available. Status check failed for url %s",
                target.getName(), target.getStatusUrl()));
      } finally {
        if (client != null) {
          HttpConnectionManager mgr = client.getHttpConnectionManager();
          if (mgr instanceof SimpleHttpConnectionManager) {
            ((SimpleHttpConnectionManager) mgr).shutdown();
          }
        }
        if (getMethod != null) {
          getMethod.releaseConnection();
        }
        getMethod = null;
        client = null;
      }
    }
    return connOk;
  }

  @Override
  public long getTargetVersion(PublishingTargetItem target, String site) {
    long version = -1;
    if (target.getVersionUrl() != null && !target.getVersionUrl().isEmpty()) {
      LOGGER.debug(String.format("Get deployment agent version for target ", target.getName()));
      URL versionUrl = null;
      try {
        versionUrl = new URL(target.getVersionUrl());
      } catch (MalformedURLException e) {
        LOGGER.error(String.format("Invalid get version URL for target [%s]", target.getName()), e);
      }
      GetMethod getMethod = null;
      HttpClient client = null;
      try {
        getMethod = new GetMethod(target.getVersionUrl());
        String siteId = target.getSiteId();
        if (StringUtils.isEmpty(siteId)) {
          siteId = site;
        }
        getMethod.setQueryString(
            new NameValuePair[] {
              new NameValuePair(TARGET_REQUEST_PARAMETER, target.getTarget()),
              new NameValuePair(SITE_REQUEST_PARAMETER, siteId)
            });
        client = new HttpClient();
        int status = client.executeMethod(getMethod);
        if (status == HttpStatus.SC_OK) {
          String responseText = getMethod.getResponseBodyAsString();
          if (responseText != null && !responseText.isEmpty()) {
            version = Long.parseLong(responseText.trim());
          } else {
            version = 0;
          }
        }

      } catch (Exception e) {
        // LOGGER.error(String.format("Target (%s) responded with error while checking target
        // version. Get version failed for url %s", target.getName(), target.getVersionUrl()));

      } finally {
        if (client != null) {
          HttpConnectionManager mgr = client.getHttpConnectionManager();
          if (mgr instanceof SimpleHttpConnectionManager) {
            ((SimpleHttpConnectionManager) mgr).shutdown();
          }
        }
        if (getMethod != null) {
          getMethod.releaseConnection();
        }
        getMethod = null;
        client = null;
      }
    }
    return version;
  }

  @Override
  public List<PublishingSyncItem> getItemsToSync(
      String site, long targetVersion, List<String> environments) {
    return _deploymentDAL.getItemsReadyForTargetSync(site, targetVersion, environments);
  }

  @Override
  public void deployItemsToTarget(
      String site, List<PublishingSyncItem> filteredItems, PublishingTargetItem target)
      throws ContentNotFoundForPublishingException, UploadFailedException {
    LOGGER.debug(
        "Start deploying items for site \"{0}\", target \"{1}\", number of items \"{2}\"",
        site, target.getName(), filteredItems.size());
    URL requestUrl = null;
    try {
      requestUrl = new URL(target.getServerUrl());
    } catch (MalformedURLException e) {
      LOGGER.error("Invalid server URL for target {0}", target.getName());
      throw new UploadFailedException(site, target.getName(), target.getServerUrl(), e);
    }

    ByteArrayPartSource baps = null;
    PartSource metadataPart = null;
    StringPart stringPart = null;
    FilePart filePart = null;

    int numberOfBuckets = filteredItems.size() / target.getBucketSize() + 1;
    Iterator<PublishingSyncItem> iter = filteredItems.iterator();
    LOGGER.debug(
        "Divide all deployment items into {0} bucket(s) for  target {1}",
        numberOfBuckets, target.getName());
    List<DeploymentEventItem> eventItems = new ArrayList<DeploymentEventItem>();
    for (int bucketIndex = 0; bucketIndex < numberOfBuckets; bucketIndex++) {
      int cntFiles = 0;
      StringBuilder sbDeletedFiles = new StringBuilder();
      List<Part> formParts = new ArrayList<Part>();

      formParts.add(new StringPart(PASSWORD_REQUEST_PARAMETER, target.getPassword()));
      formParts.add(new StringPart(TARGET_REQUEST_PARAMETER, target.getTarget()));
      String siteId = target.getSiteId();
      if (StringUtils.isEmpty(siteId)) {
        siteId = site;
      }
      formParts.add(new StringPart(SITE_REQUEST_PARAMETER, siteId));

      LOGGER.debug(
          "Preparing deployment items (bucket {0}) for target {1}",
          bucketIndex + 1, target.getName());

      int loopSize =
          (filteredItems.size() - (bucketIndex * target.getBucketSize()) > target.getBucketSize())
              ? target.getBucketSize()
              : filteredItems.size() - bucketIndex * target.getBucketSize();
      for (int j = 0; j < loopSize; j++) {
        if (iter.hasNext()) {

          PublishingSyncItem item = iter.next();
          LOGGER.debug(
              "Parsing \"{0}\" , site \"{1}\"; for publishing on target \"{2}\"",
              item.getPath(), item.getSite(), target.getName());
          DeploymentEventItem eventItem = new DeploymentEventItem();
          eventItem.setSite(item.getSite());
          eventItem.setPath(item.getPath());
          eventItem.setUser(item.getUser());
          eventItem.setDateTime(new Date());

          if (item.getAction() == PublishingSyncItem.Action.DELETE) {
            eventItem.setState(DeploymentEventItem.STATE_DELETED);
            if (sbDeletedFiles.length() > 0) {
              sbDeletedFiles.append(FILES_SEPARATOR).append(item.getPath());
            } else {
              sbDeletedFiles.append(item.getPath());
            }
            if (item.getPath().endsWith("/" + _indexFile)) {
              sbDeletedFiles
                  .append(FILES_SEPARATOR)
                  .append(item.getPath().replace("/" + _indexFile, ""));
            }
          } else {

            if (item.getAction() == PublishingSyncItem.Action.NEW) {
              eventItem.setState(DeploymentEventItem.STATE_NEW);
            } else if (item.getAction() == PublishingSyncItem.Action.MOVE) {
              eventItem.setState(DeploymentEventItem.STATE_MOVED);
            } else {
              eventItem.setState(DeploymentEventItem.STATE_UPDATED);
            }

            LOGGER.debug("Get content for \"{0}\" , site \"{1}\"", item.getPath(), item.getSite());
            InputStream input =
                _contentRepository.getContent(site, null, item.getEnvironment(), item.getPath());
            try {
              if (input == null || input.available() < 0) {
                if (!_contentRepository.isFolder(site, item.getPath())
                    && _contentRepository.contentExists(site, item.getPath())) {
                  baps = null;
                  stringPart = null;
                  filePart = null;
                  formParts = null;
                  throw new ContentNotFoundForPublishingException(
                      site, target.getName(), item.getPath());
                } else {
                  // Content does not exist - skip deploying file
                  continue;
                }
              }
            } catch (IOException err) {
              LOGGER.error(
                  "Error reading input stream for content at path: "
                      + item.getPath()
                      + " site: "
                      + item.getSite());
              if (_contentRepository.contentExists(site, item.getPath())) {
                baps = null;
                stringPart = null;
                filePart = null;
                formParts = null;
                throw new ContentNotFoundForPublishingException(
                    site, target.getName(), item.getPath());
              } else {
                // Content does not exist - skip deploying file
                continue;
              }
            }
            String fileName = _contentRepository.getFilename(site, item.getPath());

            byte[] byteArray = null;

            try {
              byteArray = IOUtils.toByteArray(input);
            } catch (IOException e) {
              LOGGER.error("Error while converting input stream to byte array", e);
              baps = null;
              stringPart = null;
              filePart = null;
              formParts = null;
              if (_contentRepository.contentExists(site, item.getPath())) {
                throw new ContentNotFoundForPublishingException(
                    site, target.getName(), item.getPath());
              } else {
                // Content does not exist - skip deploying file
                continue;
              }
            } finally {
              IOUtils.closeQuietly(input);
              input = null;
            }
            baps = new ByteArrayPartSource(fileName, byteArray);

            LOGGER.debug(
                "Create http request parameters for \"{0}\" , site \"{1}\"; publishing on target \"{2}\"",
                item.getPath(), item.getSite(), target.getName());
            int idx = item.getPath().lastIndexOf("/");
            String relativePath = item.getPath().substring(0, idx + 1) + fileName;
            stringPart =
                new StringPart(CONTENT_LOCATION_REQUEST_PARAMETER + cntFiles, relativePath);
            formParts.add(stringPart);
            filePart = new FilePart(CONTENT_FILE_REQUEST_PARAMETER + cntFiles, baps);
            formParts.add(filePart);
            if (item.getAction() == PublishingSyncItem.Action.MOVE) {
              if (item.getOldPath() != null
                  && !item.getOldPath().equalsIgnoreCase(item.getPath())) {
                LOGGER.debug(
                    "Add old path to be deleted for MOVE action (\"{0}\")", item.getOldPath());
                eventItem.setOldPath(item.getOldPath());
                if (sbDeletedFiles.length() > 0) {
                  sbDeletedFiles.append(",").append(item.getOldPath());
                } else {
                  sbDeletedFiles.append(item.getOldPath());
                }
                if (item.getOldPath().endsWith("/" + _indexFile)) {
                  sbDeletedFiles
                      .append(FILES_SEPARATOR)
                      .append(item.getOldPath().replace("/" + _indexFile, ""));
                }
              }
            }

            if (target.isSendMetadata()) {
              LOGGER.debug(
                  "Adding meta data for content \"{0}\" site \"{0}\"",
                  item.getPath(), item.getSite());
              InputStream metadataStream = null;
              try {
                metadataStream = _contentRepository.getMetadataStream(site, item.getPath());
                metadataPart =
                    new ByteArrayPartSource(
                        fileName + ".meta", IOUtils.toByteArray(metadataStream));
                formParts.add(
                    new FilePart(METADATA_FILE_REQUEST_PARAMETER + cntFiles, metadataPart));
              } catch (IOException e) {
                LOGGER.error("Error while creating input stream with content metadata", e);
                baps = null;
                stringPart = null;
                filePart = null;
                formParts = null;
              } finally {
                IOUtils.closeQuietly(metadataStream);
                metadataPart = null;
              }
            }
          }
          cntFiles++;
          eventItems.add(eventItem);
        }
      }

      if (sbDeletedFiles.length() > 0) {
        formParts.add(new StringPart(DELETED_FILES_REQUEST_PARAMETER, sbDeletedFiles.toString()));
      }
      LOGGER.debug(
          "Create http request to deploy bucket {0} for target {1}",
          bucketIndex + 1, target.getName());

      PostMethod postMethod = null;
      HttpClient client = null;
      try {

        LOGGER.debug("Create HTTP Post Method");
        postMethod = new PostMethod(requestUrl.toString());
        postMethod.getParams().setBooleanParameter(HttpMethodParams.USE_EXPECT_CONTINUE, true);
        Part[] parts = new Part[formParts.size()];
        for (int i = 0; i < formParts.size(); i++) parts[i] = formParts.get(i);
        postMethod.setRequestEntity(new MultipartRequestEntity(parts, postMethod.getParams()));
        client = new HttpClient();

        LOGGER.debug("Execute HTTP POST request \"{0}\"", postMethod.getURI());
        int status = client.executeMethod(postMethod);
        if (status == HttpStatus.SC_OK) {
          LOGGER.info(
              "Successfully deployed bucket number {0} on target {1}",
              bucketIndex + 1, target.getName());
        } else {
          LOGGER.error(
              "Deployment failed for bucket number {0} on target {1}. Deployment agent returned status {2}",
              bucketIndex + 1, target.getName(), HttpStatus.getStatusText(status));
          throw new UploadFailedException(site, target.getName(), target.getServerUrl());
        }
      } catch (HttpException e) {
        LOGGER.error(
            "Publish failed for target {0} due to http protocol exception", target.getName());
        throw new UploadFailedException(site, target.getName(), target.getServerUrl(), e);
      } catch (IOException e) {
        LOGGER.error(
            "Publish failed for target {0} due to I/O (transport) exception", target.getName());
        throw new UploadFailedException(site, target.getName(), target.getServerUrl(), e);
      } finally {
        LOGGER.debug("Release http connection and release resources");
        if (client != null) {
          HttpConnectionManager mgr = client.getHttpConnectionManager();
          if (mgr instanceof SimpleHttpConnectionManager) {
            ((SimpleHttpConnectionManager) mgr).shutdown();
          }
        }
        if (postMethod != null) {
          postMethod.releaseConnection();
          postMethod = null;
          client = null;
        }
        baps = null;
        stringPart = null;
        filePart = null;
        formParts = null;
      }
    }

    LOGGER.debug(
        "Publishing deployment event for target \"{0}\" with \"{1}\" items.",
        target.getName(), eventItems.size());
    _contentRepository.publishDeployEvent(target.getName(), eventItems);

    LOGGER.info("Deployment successful on target {0}", target.getName());
    LOGGER.debug(
        "Finished deploying items for site \"{0}\", target \"{1}\", number of items \"{2}\"",
        site, target.getName(), filteredItems.size());
  }

  @Override
  public long setTargetVersion(PublishingTargetItem target, long newVersion, String site) {
    long resoponseVersion = -1;
    if (target.getVersionUrl() != null && !target.getVersionUrl().isEmpty()) {
      LOGGER.debug("Set deployment agent version for target {0}", target.getName());
      URL versionUrl = null;
      try {
        versionUrl = new URL(target.getVersionUrl());
      } catch (MalformedURLException e) {
        LOGGER.error("Invalid set version URL for target [%s]", target.getName());
        return resoponseVersion;
      }
      PostMethod postMethod = null;
      HttpClient client = null;
      try {
        postMethod = new PostMethod(target.getVersionUrl());
        postMethod.addParameter(TARGET_REQUEST_PARAMETER, target.getTarget());
        postMethod.addParameter(VERSION_REQUEST_PARAMETER, String.valueOf(newVersion));
        String siteId = target.getSiteId();
        if (StringUtils.isEmpty(siteId)) {
          siteId = site;
        }
        postMethod.addParameter(SITE_REQUEST_PARAMETER, site);
        client = new HttpClient();
        int status = client.executeMethod(postMethod);
        if (status == HttpStatus.SC_OK) {
          String responseText = postMethod.getResponseBodyAsString();
          if (responseText != null && !responseText.isEmpty()) {
            resoponseVersion = Long.parseLong(responseText);
          } else {
            resoponseVersion = 0;
          }
        }

      } catch (Exception e) {
        LOGGER.error(
            "Target {0} responded with error while setting target version. Set version failed for url {1}",
            target.getName(), target.getVersionUrl());

      } finally {
        if (client != null) {
          HttpConnectionManager mgr = client.getHttpConnectionManager();
          if (mgr instanceof SimpleHttpConnectionManager) {
            ((SimpleHttpConnectionManager) mgr).shutdown();
          }
        }
        if (postMethod != null) {
          postMethod.releaseConnection();
        }
        postMethod = null;
        client = null;
      }
    }
    return resoponseVersion;
  }

  @Override
  public List<CopyToEnvironmentItem> getItemsReadyForDeployment(String site, String environment) {
    return _deploymentDAL.getItemsReadyForDeployment(site, environment);
  }

  @Override
  public void processItem(CopyToEnvironmentItem item) throws DeploymentException {
    String liveEnvironment = _contentRepository.getLiveEnvironmentName(item.getSite());
    boolean isLive = false;
    if (StringUtils.isNotEmpty(liveEnvironment)) {
      if (liveEnvironment.equals(item.getEnvironment())) {
        isLive = true;
      }
    } else if (LIVE_ENVIRONMENT.equalsIgnoreCase(item.getEnvironment())
        || PRODUCTION_ENVIRONMENT.equalsIgnoreCase(item.getEnvironment())) {
      isLive = true;
    }
    if (item.getAction() == CopyToEnvironmentItem.Action.DELETE) {
      if (item.getOldPath() != null && item.getOldPath().length() > 0) {
        _contentRepository.deleteContent(item.getSite(), item.getEnvironment(), item.getOldPath());
        _contentRepository.clearRenamed(item.getSite(), item.getPath());
      }
      _contentRepository.deleteContent(item.getSite(), item.getEnvironment(), item.getPath());
      if (isLive) {
        _contentRepository.deleteContent(item);
      }
    } else {
      _contentRepository.setSystemProcessing(item.getSite(), item.getPath(), true);
      if (isLive) {
        if (!_importModeEnabled) {
          _contentRepository.createNewVersion(
              item.getSite(), item.getPath(), item.getSubmissionComment(), true);
        } else {
          LOGGER.debug(
              "Import mode is ON. Create new version is skipped for [{0}] site \"{1}\"",
              item.getPath(), item.getSite());
        }
      }
      if (item.getAction() == CopyToEnvironmentItem.Action.MOVE) {
        if (item.getOldPath() != null && item.getOldPath().length() > 0) {
          _contentRepository.deleteContent(
              item.getSite(), item.getEnvironment(), item.getOldPath());
          if (isLive) {
            _contentRepository.clearRenamed(item.getSite(), item.getPath());
          }
        }
      }
      _contentRepository.copyToEnvironment(item.getSite(), item.getEnvironment(), item.getPath());
      if (isLive) {
        _contentRepository.stateTransition(
            item.getSite(), item.getPath(), TransitionEvent.DEPLOYMENT);
      }
      _contentRepository.setSystemProcessing(item.getSite(), item.getPath(), false);
    }
  }

  @Override
  public void setLockBehaviourEnabled(boolean enabled) {
    _contentRepository.setLockBehaviourEnabled(enabled);
  }

  @Override
  public void setupItemsForPublishingSync(
      String site, String environment, List<CopyToEnvironmentItem> itemsToDeploy)
      throws DeploymentException {
    _deploymentDAL.setupItemsForPublishingSync(site, environment, itemsToDeploy);
  }

  @Override
  public void insertDeploymentHistory(
      PublishingTargetItem target, List<PublishingSyncItem> publishedItems, Date publishingDate)
      throws DeploymentException {
    _deploymentDAL.insertDeploymentHistory(target, publishedItems, publishingDate);
  }

  @Override
  public void markItemsCompleted(
      String site, String environment, List<CopyToEnvironmentItem> processedItems)
      throws DeploymentException {
    _deploymentDAL.markItemsCompleted(site, environment, processedItems);
  }

  @Override
  public void markItemsProcessing(
      String site, String environment, List<CopyToEnvironmentItem> itemsToDeploy)
      throws DeploymentException {
    _deploymentDAL.markItemsProcessing(site, environment, itemsToDeploy);
  }

  @Override
  public void markItemsReady(
      String site, String environment, List<CopyToEnvironmentItem> copyToEnvironmentItems)
      throws DeploymentException {
    _deploymentDAL.markItemsReady(site, environment, copyToEnvironmentItems);
  }

  @Override
  public List<CopyToEnvironmentItem> processMandatoryDependencies(
      CopyToEnvironmentItem item, List<String> pathsToDeploy, Set<String> missingDependenciesPaths)
      throws DeploymentException {
    List<CopyToEnvironmentItem> mandatoryDependencies = new ArrayList<CopyToEnvironmentItem>();
    String site = item.getSite();
    String path = item.getPath();
    if (item.getAction() == CopyToEnvironmentItem.Action.NEW
        || item.getAction() == CopyToEnvironmentItem.Action.MOVE) {
      String helpPath = path.replace("/" + _indexFile, "");
      int idx = helpPath.lastIndexOf("/");
      String parentPath = helpPath.substring(0, idx) + "/" + _indexFile;
      if (_contentRepository.isNew(site, parentPath)
          || _contentRepository.isRenamed(site, parentPath)) {
        String parentFullPath = _contentRepository.getFullPath(site, parentPath);
        if (!missingDependenciesPaths.contains(parentFullPath)
            && !pathsToDeploy.contains(parentFullPath)) {
          try {
            _deploymentDAL.cancelWorkflow(site, parentPath);
          } catch (DeploymentDALException e) {
            LOGGER.error(
                "Error while canceling workflow for path {0}, site {1}", e, site, parentPath);
          }
          missingDependenciesPaths.add(parentFullPath);
          CopyToEnvironmentItem parentItem = createMissingItem(site, parentPath, item);
          processItem(parentItem);
          mandatoryDependencies.add(parentItem);
          mandatoryDependencies.addAll(
              processMandatoryDependencies(parentItem, pathsToDeploy, missingDependenciesPaths));
        }
      }

      List<String> dependentPaths = _contentRepository.getDependentPaths(site, path);
      for (String dependentPath : dependentPaths) {
        if (_contentRepository.isNew(site, dependentPath)
            || _contentRepository.isRenamed(site, dependentPath)) {
          String dependentFullPath = _contentRepository.getFullPath(site, dependentPath);
          if (!missingDependenciesPaths.contains(dependentFullPath)
              && !pathsToDeploy.contains(dependentFullPath)) {
            try {
              _deploymentDAL.cancelWorkflow(site, dependentPath);
            } catch (DeploymentDALException e) {
              LOGGER.error(
                  "Error while canceling workflow for path {0}, site {1}", e, site, dependentPath);
            }
            missingDependenciesPaths.add(dependentFullPath);
            CopyToEnvironmentItem dependentItem = createMissingItem(site, dependentPath, item);
            processItem(dependentItem);
            mandatoryDependencies.add(dependentItem);
            mandatoryDependencies.addAll(
                processMandatoryDependencies(
                    dependentItem, pathsToDeploy, missingDependenciesPaths));
          }
        }
      }
    }

    return mandatoryDependencies;
  }

  private CopyToEnvironmentItem createMissingItem(
      String site, String itemPath, CopyToEnvironmentItem item) {
    CopyToEnvironmentItem missingItem = new CopyToEnvironmentItem();
    missingItem.setSite(site);
    missingItem.setEnvironment(item.getEnvironment());
    missingItem.setPath(itemPath);
    missingItem.setScheduledDate(item.getScheduledDate());
    missingItem.setState(item.getState());
    if (_contentRepository.isNew(site, itemPath)) {
      missingItem.setAction(CopyToEnvironmentItem.Action.NEW);
    }
    if (_contentRepository.isRenamed(site, itemPath)) {
      String oldPath = _contentRepository.getOldPath(site, itemPath);
      missingItem.setOldPath(oldPath);
      missingItem.setAction(CopyToEnvironmentItem.Action.MOVE);
    }
    String contentTypeClass = _contentRepository.getContentTypeClass(site, itemPath);
    missingItem.setContentTypeClass(contentTypeClass);
    missingItem.setUser(item.getUser());
    missingItem.setSubmissionComment(item.getSubmissionComment());
    return missingItem;
  }

  public ContentRepository getContentRepository() {
    return _contentRepository;
  }

  public void setContentRepository(ContentRepository contentRepository) {
    this._contentRepository = contentRepository;
  }

  public DeploymentDAL getDeploymentDal() {
    return _deploymentDAL;
  }

  public void setDeploymentDAL(DeploymentDAL deploymentDAL) {
    this._deploymentDAL = deploymentDAL;
  }

  public String getIndexFile() {
    return _indexFile;
  }

  public void setIndexFile(String indexFile) {
    this._indexFile = indexFile;
  }

  public boolean isImportModeEnabled() {
    return _importModeEnabled;
  }

  public void setImportModeEnabled(boolean importModeEnabled) {
    this._importModeEnabled = importModeEnabled;
    LOGGER.info(
        "Import mode is {0}. Creating new version when deploying content is {1}",
        _importModeEnabled ? "ON" : "OFF", _importModeEnabled ? "DISABLED" : "ENABLED");
  }

  protected ContentRepository _contentRepository;
  protected DeploymentDAL _deploymentDAL;
  protected String _indexFile;
  protected boolean _importModeEnabled;
}
/**
 * Alfresco repository implementation. This is the only point of contact with Alfresco's API in the
 * entire system under the org.craftercms.cstudio.impl package structure
 *
 * @author russdanner
 */
public class AlfrescoContentRepository extends AbstractContentRepository {

  protected static final String MSG_ERROR_RUN_AS_FAILED = "err_alfresco_run_as_failure";
  protected static final String MSG_NODE_REF_IS_NULL_FOR_PATH = "alfresco_noderef_null_for_path";
  protected static final String MSG_CONTENT_FOR_FOLDER_REQUESTED =
      "alfresco_content_for_folder_requested";

  private static final Logger logger = LoggerFactory.getLogger(AlfrescoContentRepository.class);

  /**
   * perform operation as a specific user
   *
   * @param userName the name of the user account performing the operation
   * @param obj the object that contains the method to executre
   * @param work the method that represents the work to perform
   * @param args any number of arguments to pass to the method
   */
  private static final String SITE_REPO_ROOT_PATTERN = "/wem-projects/{site}/{site}/work-area";

  private static final String SITE_ENVIRONMENT_ROOT_PATTERN =
      "/wem-projects/{site}/{site}/{environment}";
  private static final String SITE_REPLACEMENT_PATTERN = "\\{site\\}";
  private static final String ENVIRONMENT_REPLACEMENT_PATTERN = "\\{environment\\}";
  private static final String WORK_AREA_REPOSITORY = "work-area";
  private static final String LIVE_REPOSITORY = "live";

  public Object runAs(
      final String userName, final Object obj, final Method work, final Object... args) {

    Object retObject = null;

    // need to check params for nulls

    try {
      retObject =
          AuthenticationUtil.runAs(
              new AuthenticationUtil.RunAsWork<Object>() {
                public Object doWork() {
                  Object retValue = null;

                  try {
                    retValue = work.invoke(obj, null);
                  } catch (Exception err) {
                    logger.error(MSG_ERROR_RUN_AS_FAILED, err, userName, obj.getClass().getName());
                  }

                  return retValue;
                }
              },
              userName);
    } catch (Exception err) {
      logger.error(MSG_ERROR_RUN_AS_FAILED, err, userName, obj.getClass().getName());
    }

    return retObject;
  }

  /** get transaction */
  public UserTransaction getTransaction() {
    return _transactionService.getUserTransaction();
  }

  /** @return true if site has content object at path */
  public boolean contentExists(String site, String path) {

    return _dmContentService.contentExists(site, path, path);
  }

  /**
   * get document from wcm content
   *
   * @param path
   * @return document
   * @throws ServiceException
   */
  public InputStream getContent(String path) {
    InputStream retStream = null;
    PersistenceManagerService persistenceManagerService =
        _servicesManager.getService(PersistenceManagerService.class);
    NodeRef nodeRef = persistenceManagerService.getNodeRef(path);

    if (nodeRef != null) {
      FileInfo fileInfo = persistenceManagerService.getFileInfo(nodeRef);
      if (fileInfo.isFolder()) {
        logger.info(MSG_CONTENT_FOR_FOLDER_REQUESTED, path);
      } else {
        ContentReader reader = persistenceManagerService.getReader(nodeRef);
        retStream = reader.getContentInputStream();
      }
    } else {
      logger.info(MSG_NODE_REF_IS_NULL_FOR_PATH, path);
    }

    return retStream;
  }

  public void writeContent(String path, InputStream content) {
    PersistenceManagerService persistenceManagerService =
        _servicesManager.getService(PersistenceManagerService.class);
    // NodeRef nodeRef = persistenceManagerService.getNodeRef(path);

    // if (nodeRef != null) {
    ContentWriter writer = persistenceManagerService.getWriter(path);
    writer.putContent(content);
    // }
  }

  @Override
  public void stateTransition(String site, List<String> paths, TransitionEvent event) {
    PersistenceManagerService persistenceManagerService =
        _servicesManager.getService(PersistenceManagerService.class);
    List<String> objectIds = new ArrayList<String>();
    String rootPath = SITE_REPO_ROOT_PATTERN.replaceAll(SITE_REPLACEMENT_PATTERN, site);
    for (String relativePath : paths) {
      NodeRef nodeRef = persistenceManagerService.getNodeRef(rootPath, relativePath);
      if (nodeRef != null) {
        objectIds.add(nodeRef.getId());
      }
    }
    ObjectStateService.TransitionEvent convertedEvent = eventConversionMap.get(event);
    ObjectStateService.State defaultState = defaultStateForEvent.get(event);
    persistenceManagerService.transitionBulk(objectIds, convertedEvent, defaultState);
  }

  @Override
  public void stateTransition(String site, String path, TransitionEvent event) {
    PersistenceManagerService persistenceManagerService =
        _servicesManager.getService(PersistenceManagerService.class);
    List<String> objectIds = new ArrayList<String>();
    String rootPath = SITE_REPO_ROOT_PATTERN.replaceAll(SITE_REPLACEMENT_PATTERN, site);
    NodeRef nodeRef = persistenceManagerService.getNodeRef(rootPath, path);
    if (nodeRef != null) {
      ObjectStateService.TransitionEvent convertedEvent = eventConversionMap.get(event);
      persistenceManagerService.transition(nodeRef, convertedEvent);
    }
  }

  private final Map<TransitionEvent, ObjectStateService.TransitionEvent> eventConversionMap =
      new HashMap<TransitionEvent, ObjectStateService.TransitionEvent>() {
        {
          put(
              TransitionEvent.SCHEDULED_DEPLOYMENT,
              ObjectStateService.TransitionEvent.SUBMIT_WITHOUT_WORKFLOW_SCHEDULED);
          put(TransitionEvent.DEPLOYMENT, ObjectStateService.TransitionEvent.DEPLOYMENT);
          put(TransitionEvent.DELETE, ObjectStateService.TransitionEvent.DELETE);
        }
      };

  private final Map<TransitionEvent, ObjectStateService.State> defaultStateForEvent =
      new HashMap<TransitionEvent, ObjectStateService.State>() {
        {
          put(
              TransitionEvent.SCHEDULED_DEPLOYMENT,
              ObjectStateService.State.NEW_SUBMITTED_NO_WF_SCHEDULED);
          put(TransitionEvent.DEPLOYMENT, ObjectStateService.State.EXISTING_UNEDITED_UNLOCKED);
          put(TransitionEvent.DELETE, ObjectStateService.State.EXISTING_DELETED);
        }
      };

  @Override
  public void setSystemProcessing(String site, List<String> paths, boolean isSystemProcessing) {
    PersistenceManagerService persistenceManagerService =
        _servicesManager.getService(PersistenceManagerService.class);
    List<String> objectIds = new ArrayList<String>();
    String rootPath = SITE_REPO_ROOT_PATTERN.replaceAll(SITE_REPLACEMENT_PATTERN, site);
    for (String relativePath : paths) {
      NodeRef nodeRef = persistenceManagerService.getNodeRef(rootPath, relativePath);
      if (nodeRef != null) {
        objectIds.add(nodeRef.getId());
      }
    }
    persistenceManagerService.setSystemProcessingBulk(objectIds, isSystemProcessing);
  }

  @Override
  public void setSystemProcessing(String site, String path, boolean isSystemProcessing) {
    PersistenceManagerService persistenceManagerService =
        _servicesManager.getService(PersistenceManagerService.class);
    String rootPath = SITE_REPO_ROOT_PATTERN.replaceAll(SITE_REPLACEMENT_PATTERN, site);
    NodeRef nodeRef = persistenceManagerService.getNodeRef(rootPath, path);
    if (nodeRef != null) {
      persistenceManagerService.setSystemProcessing(nodeRef, isSystemProcessing);
    }
  }

  @Override
  public void createNewVersion(
      String site, String path, String submissionComment, boolean isMajorVersion) {
    PersistenceManagerService persistenceManagerService =
        _servicesManager.getService(PersistenceManagerService.class);
    String rootPath = SITE_REPO_ROOT_PATTERN.replaceAll(SITE_REPLACEMENT_PATTERN, site);
    NodeRef nodeRef = persistenceManagerService.getNodeRef(rootPath, path);
    if (nodeRef != null) {
      DmVersionService dmVersionService = _servicesManager.getService(DmVersionService.class);
      if (isMajorVersion) {
        dmVersionService.createNextMajorVersion(site, path, submissionComment);
      } else {
        dmVersionService.createNextMinorVersion(site, path);
      }
    }
  }

  @Override
  public void setLockBehaviourEnabled(boolean enabled) {
    PersistenceManagerService persistenceManagerService =
        _servicesManager.getService(PersistenceManagerService.class);
    if (enabled) {
      persistenceManagerService.enableBehaviour(ContentModel.ASPECT_LOCKABLE);
    } else {
      persistenceManagerService.disableBehaviour(ContentModel.ASPECT_LOCKABLE);
    }
  }

  @Override
  public void copyToEnvironment(String site, String environment, String path)
      throws DeploymentException {
    ServicesConfig servicesConfig = getServicesManager().getService(ServicesConfig.class);
    PersistenceManagerService persistenceManagerService =
        getServicesManager().getService(PersistenceManagerService.class);
    String siteRepoRootPath = SITE_REPO_ROOT_PATTERN.replaceAll(SITE_REPLACEMENT_PATTERN, site);

    String envRepoPath = SITE_ENVIRONMENT_ROOT_PATTERN.replaceAll(SITE_REPLACEMENT_PATTERN, site);
    envRepoPath = envRepoPath.replaceAll(ENVIRONMENT_REPLACEMENT_PATTERN, environment);

    NodeRef envRepoRoot = persistenceManagerService.getNodeRef(envRepoPath);

    NodeRef envNode = persistenceManagerService.getNodeRef(envRepoRoot, path);
    NodeRef nodeRef = persistenceManagerService.getNodeRef(siteRepoRootPath, path);
    if (nodeRef != null) {
      if (envNode == null) {
        envNode = createLiveRepositoryCopy(envRepoRoot, path, nodeRef);
      } else {
        FileInfo envNodeInfo = persistenceManagerService.getFileInfo(envNode);
        if (envNodeInfo.isFolder()) {
          Map<QName, Serializable> copyNodeProps = persistenceManagerService.getProperties(nodeRef);
          copyNodeProps.put(ContentModel.PROP_NAME, envNodeInfo.getName());
          persistenceManagerService.setProperties(envNode, copyNodeProps);
        } else {
          persistenceManagerService.copy(nodeRef, envNode);
        }
      }
      Serializable sendEmailValue =
          persistenceManagerService.getProperty(
              nodeRef, CStudioContentModel.PROP_WEB_WF_SEND_EMAIL);
      boolean sendEmail = (sendEmailValue != null) && (Boolean) sendEmailValue;

      if (sendEmail) {
        Serializable submittedByValue =
            persistenceManagerService.getProperty(
                nodeRef, CStudioContentModel.PROP_WEB_WF_SUBMITTED_BY);
        String submittedBy = "";
        if (submittedByValue != null) {
          submittedBy = (String) submittedByValue;
        } else {
          logger.error("did not send approval notification as submitted by property is null");
          return;
        }
        // DmPathTO path = new DmPathTO(nodePath);
        String approver =
            (String)
                persistenceManagerService.getProperty(
                    nodeRef, CStudioContentModel.PROP_WEB_APPROVED_BY);
        NotificationService notificationService =
            getServicesManager().getService(NotificationService.class);
        notificationService.sendApprovalNotification(site, submittedBy, path, approver);
        /*
         * Remove this sendmail property as we are done sending email
         */
        persistenceManagerService.removeProperty(
            nodeRef, CStudioContentModel.PROP_WEB_WF_SEND_EMAIL);
      }

      Map<QName, Serializable> nodeProps = persistenceManagerService.getProperties(envNode);
      for (QName propName : DmConstants.SUBMITTED_PROPERTIES) {
        nodeProps.remove(propName);
      }
      persistenceManagerService.setProperties(envNode, nodeProps);

      nodeProps = persistenceManagerService.getProperties(nodeRef);
      for (QName propName : DmConstants.SUBMITTED_PROPERTIES) {
        nodeProps.remove(propName);
      }
      persistenceManagerService.setProperties(nodeRef, nodeProps);
    }
  }

  protected NodeRef createEnvRepository(String site, String envRepoName) {
    PersistenceManagerService persistenceManagerService =
        getServicesManager().getService(PersistenceManagerService.class);
    String siteRoot = SITE_ENVIRONMENT_ROOT_PATTERN.replaceAll(SITE_REPLACEMENT_PATTERN, site);
    siteRoot = siteRoot.replaceAll(ENVIRONMENT_REPLACEMENT_PATTERN, "");
    NodeRef siteRootNode = persistenceManagerService.getNodeRef(siteRoot);
    NodeRef result = persistenceManagerService.createNewFolder(siteRootNode, envRepoName);
    return result;
  }

  protected NodeRef createLiveRepositoryCopy(
      NodeRef liveRepoRoot, String relativePath, NodeRef nodeRef) {
    logger.debug("[PUBLISHING POST PROCESSOR] creating live repository copy of " + relativePath);
    PersistenceManagerService persistenceManagerService =
        getServicesManager().getService(PersistenceManagerService.class);
    NodeRef result = null;

    String[] pathSegments = relativePath.split("/");
    NodeRef helperNode = liveRepoRoot;
    NodeRef parent = null;
    for (int i = 0; i < pathSegments.length - 1; i++) {
      if (!"".equals(pathSegments[i])) {
        parent = helperNode;
        helperNode =
            persistenceManagerService.getChildByName(
                helperNode, ContentModel.ASSOC_CONTAINS, pathSegments[i]);
        if (helperNode == null) {
          logger.debug("[WORKFLOW] creating a node with name: " + pathSegments[i]);
          Map<QName, Serializable> properties = new FastMap<QName, Serializable>();
          properties.put(ContentModel.PROP_NAME, pathSegments[i]);
          helperNode =
              persistenceManagerService.createNewFolder(parent, pathSegments[i], properties);
        }
      }
    }
    String nodeName =
        (String) persistenceManagerService.getProperty(nodeRef, ContentModel.PROP_NAME);
    QName assocQName =
        QName.createQName(
            ContentModel.TYPE_CONTENT.getNamespaceURI(), QName.createValidLocalName(nodeName));
    result =
        persistenceManagerService.copy(
            nodeRef, helperNode, ContentModel.ASSOC_CONTAINS, assocQName);
    persistenceManagerService.setProperty(result, ContentModel.PROP_NAME, nodeName);
    return result;
  }

  @Override
  public Set<String> getAllAvailableSites() {
    SiteService siteService = _servicesManager.getService(SiteService.class);
    return siteService.getAllAvailableSites();
  }

  @Override
  public Set<PublishingTargetItem> getAllTargetsForSite(String site) {
    PersistenceManagerService persistenceManagerService =
        _servicesManager.getService(PersistenceManagerService.class);
    SiteService siteService = _servicesManager.getService(SiteService.class);
    Map<String, PublishingChannelGroupConfigTO> groupConfigTOs =
        siteService.getPublishingChannelGroupConfigs(site);
    Set<PublishingTargetItem> targets = new HashSet<PublishingTargetItem>();
    Map<String, PublishingTargetItem> targetMap = new HashMap<String, PublishingTargetItem>();
    if (groupConfigTOs != null && groupConfigTOs.size() > 0) {
      for (PublishingChannelGroupConfigTO groupConfigTO : groupConfigTOs.values()) {
        List<PublishingChannelConfigTO> channelConfigTOs = groupConfigTO.getChannels();
        if (channelConfigTOs != null && channelConfigTOs.size() > 0) {
          for (PublishingChannelConfigTO channelConfigTO : channelConfigTOs) {
            DeploymentEndpointConfigTO endpoint =
                siteService.getDeploymentEndpoint(site, channelConfigTO.getName());
            if (endpoint != null) {
              PublishingTargetItem targetItem = targetMap.get(endpoint.getName());
              if (targetItem == null) {
                targetItem = new PublishingTargetItem();
                targetItem.setId(endpoint.getName());
                targetItem.setName(endpoint.getName());
                targetItem.setTarget(endpoint.getTarget());
                targetItem.setType(endpoint.getType());
                targetItem.setServerUrl(endpoint.getServerUrl());
                targetItem.setStatusUrl(endpoint.getStatusUrl());
                targetItem.setVersionUrl(endpoint.getVersionUrl());
                targetItem.setPassword(endpoint.getPassword());
                targetItem.setExcludePattern(endpoint.getExcludePattern());
                targetItem.setIncludePattern(endpoint.getIncludePattern());
                targetItem.setBucketSize(endpoint.getBucketSize());
                targetItem.setSiteId(endpoint.getSiteId());
                targets.add(targetItem);

                targetMap.put(endpoint.getName(), targetItem);
              }
              targetItem.addEnvironment(groupConfigTO.getName());
            }
          }
        }
      }
    }
    return targets;
  }

  @Override
  public String getCurrentUser() {
    PersistenceManagerService persistenceManagerService =
        _servicesManager.getService(PersistenceManagerService.class);
    return persistenceManagerService.getCurrentUserName();
  }

  @Override
  public String getAdministratorUser() {
    PersistenceManagerService persistenceManagerService =
        _servicesManager.getService(PersistenceManagerService.class);
    return persistenceManagerService.getAdministratorUserName();
  }

  @Override
  public boolean isNew(String site, String path) {
    PersistenceManagerService persistenceManagerService =
        _servicesManager.getService(PersistenceManagerService.class);
    String fullPath = SITE_REPO_ROOT_PATTERN.replaceAll(SITE_REPLACEMENT_PATTERN, site) + path;
    return persistenceManagerService.isNew(fullPath);
  }

  @Override
  public String getFilename(String site, String path) {
    if (path != null && !path.isEmpty()) {
      PersistenceManagerService persistenceManagerService =
          _servicesManager.getService(PersistenceManagerService.class);
      NodeRef nodeRef =
          persistenceManagerService.getNodeRef(
              SITE_REPO_ROOT_PATTERN.replaceAll(SITE_REPLACEMENT_PATTERN, site), path);
      if (nodeRef != null) {
        return DefaultTypeConverter.INSTANCE.convert(
            String.class, persistenceManagerService.getProperty(nodeRef, ContentModel.PROP_NAME));
      } else {
        int idx = path.lastIndexOf("/");
        if (idx > 0) {
          return path.substring(idx + 1);
        } else {
          return path;
        }
      }
    } else {
      return "";
    }
  }

  @Override
  public boolean isRenamed(String site, String path) {
    PersistenceManagerService persistenceManagerService =
        _servicesManager.getService(PersistenceManagerService.class);
    NodeRef nodeRef =
        persistenceManagerService.getNodeRef(
            SITE_REPO_ROOT_PATTERN.replaceAll(SITE_REPLACEMENT_PATTERN, site), path);
    if (nodeRef != null) {
      return persistenceManagerService.hasAspect(nodeRef, CStudioContentModel.ASPECT_RENAMED);
    } else {
      return false;
    }
  }

  @Override
  public String getOldPath(String site, String path) {
    PersistenceManagerService persistenceManagerService =
        _servicesManager.getService(PersistenceManagerService.class);
    NodeRef nodeRef =
        persistenceManagerService.getNodeRef(
            SITE_REPO_ROOT_PATTERN.replaceAll(SITE_REPLACEMENT_PATTERN, site), path);
    if (nodeRef != null) {
      if (persistenceManagerService.hasAspect(nodeRef, CStudioContentModel.ASPECT_RENAMED)) {
        String oldPath =
            DefaultTypeConverter.INSTANCE.convert(
                String.class,
                persistenceManagerService.getProperty(
                    nodeRef, CStudioContentModel.PROP_RENAMED_OLD_URL));
        return oldPath;
      }
    }
    return null;
  }

  @Override
  public InputStream getMetadataStream(String site, String path) {
    PersistenceManagerService persistenceManagerService =
        _servicesManager.getService(PersistenceManagerService.class);
    NodeRef nodeRef =
        persistenceManagerService.getNodeRef(
            SITE_REPO_ROOT_PATTERN.replaceAll(SITE_REPLACEMENT_PATTERN, site), path);
    Map<QName, Serializable> contentProperties = persistenceManagerService.getProperties(nodeRef);
    Document metadataDoc = DocumentHelper.createDocument();
    Element root = metadataDoc.addElement("metadata");
    for (Map.Entry<QName, Serializable> property : contentProperties.entrySet()) {
      Element elem = root.addElement(property.getKey().getLocalName());
      elem.addText(String.valueOf(property.getValue()));
    }

    return IOUtils.toInputStream(metadataDoc.asXML());
  }

  public void publishDeployEvent(String endpoint, List<DeploymentEventItem> items) {
    EventService eventService = _servicesManager.getService(EventService.class);
    JSONObject jsonObject = new JSONObject();
    jsonObject.put("endpoint", endpoint);
    jsonObject.put("items", items);
    eventService.publish(DeploymentEngineConstants.EVENT_DEPLOYMENT_ENGINE_DEPLOY, jsonObject);
  }

  @Override
  public void deleteContent(String site, String environment, String path) {
    PersistenceManagerService persistenceManagerService =
        _servicesManager.getService(PersistenceManagerService.class);
    String fullPath = SITE_ENVIRONMENT_ROOT_PATTERN.replaceAll(SITE_REPLACEMENT_PATTERN, site);
    fullPath = fullPath.replaceAll(ENVIRONMENT_REPLACEMENT_PATTERN, environment);
    fullPath = fullPath + path;
    NodeRef nodeRef = persistenceManagerService.getNodeRef(fullPath);
    if (nodeRef != null) {
      NodeRef parentNode = persistenceManagerService.getPrimaryParent(nodeRef).getParentRef();
      persistenceManagerService.deleteNode(nodeRef);
      List<FileInfo> children = persistenceManagerService.list(parentNode);
      while (children == null || children.size() < 1) {
        NodeRef helpNode = parentNode;
        parentNode = persistenceManagerService.getPrimaryParent(helpNode).getParentRef();
        persistenceManagerService.deleteNode(helpNode);
        children = persistenceManagerService.list(parentNode);
      }
    }
  }

  @Override
  public void deleteContent(CopyToEnvironmentItem item) {
    PersistenceManagerService persistenceManagerService =
        _servicesManager.getService(PersistenceManagerService.class);
    String fullPath =
        SITE_ENVIRONMENT_ROOT_PATTERN.replaceAll(SITE_REPLACEMENT_PATTERN, item.getSite());
    fullPath = fullPath.replaceAll(ENVIRONMENT_REPLACEMENT_PATTERN, WORK_AREA_REPOSITORY);
    fullPath = fullPath + item.getPath();
    NodeRef nodeRef = persistenceManagerService.getNodeRef(fullPath);
    if (nodeRef != null) {
      // _dmContentService.deleteContent(site, path, true, true, null);
      // return;
      List<String> paths = new ArrayList<String>();
      paths.add(item.getPath());
      _dmContentService.generateDeleteActivity(item.getSite(), paths, item.getUser());
      NodeRef parentNode = persistenceManagerService.getPrimaryParent(nodeRef).getParentRef();
      persistenceManagerService.deleteNode(nodeRef);
      persistenceManagerService.deleteObjectState(nodeRef.getId());
      List<FileInfo> children = persistenceManagerService.list(parentNode);
      while (children == null || children.size() < 1) {
        NodeRef helpNode = parentNode;
        parentNode = persistenceManagerService.getPrimaryParent(helpNode).getParentRef();
        persistenceManagerService.deleteNode(helpNode);
        children = persistenceManagerService.list(parentNode);
      }
    }
  }

  @Override
  public void clearRenamed(String site, String path) {
    String fullPath = SITE_REPO_ROOT_PATTERN.replaceAll(SITE_REPLACEMENT_PATTERN, site);
    fullPath = fullPath + path;
    PersistenceManagerService persistenceManagerService =
        _servicesManager.getService(PersistenceManagerService.class);
    NodeRef nodeRef = persistenceManagerService.getNodeRef(fullPath);
    if (nodeRef != null) {
      persistenceManagerService.removeAspect(fullPath, CStudioContentModel.ASPECT_RENAMED);
      Map<QName, Serializable> props = persistenceManagerService.getProperties(nodeRef);
      props.remove(CStudioContentModel.PROP_RENAMED_OLD_URL);
      persistenceManagerService.setProperties(nodeRef, props);
    }
  }

  @Override
  public String getContentTypeClass(String site, String path) {
    if (_dmFilterWrapper.accept(site, path, DmConstants.CONTENT_TYPE_COMPONENT)) {
      return DmConstants.CONTENT_TYPE_COMPONENT;
    } else if (_dmFilterWrapper.accept(site, path, DmConstants.CONTENT_TYPE_ASSET)) {
      return DmConstants.CONTENT_TYPE_ASSET;
    } else if (_dmFilterWrapper.accept(site, path, DmConstants.CONTENT_TYPE_RENDERING_TEMPLATE)) {
      return DmConstants.CONTENT_TYPE_RENDERING_TEMPLATE;
    } else if (_dmFilterWrapper.accept(site, path, DmConstants.CONTENT_TYPE_PAGE)) {
      return DmConstants.CONTENT_TYPE_PAGE;
    } else if (_dmFilterWrapper.accept(site, path, DmConstants.CONTENT_TYPE_DOCUMENT)) {
      return DmConstants.CONTENT_TYPE_DOCUMENT;
    } else {
      return DmConstants.CONTENT_TYPE_OTHER;
    }
  }

  @Override
  public String getFullPath(String site, String path) {
    String fullPath = SITE_REPO_ROOT_PATTERN.replaceAll(SITE_REPLACEMENT_PATTERN, site);
    fullPath = fullPath + path;
    return fullPath;
  }

  @Override
  public List<String> getDependentPaths(String site, String path) {
    DmDependencyService dmDependencyService =
        _servicesManager.getService(DmDependencyService.class);
    return dmDependencyService.getDependencyPaths(site, path);
  }

  @Override
  public boolean isFolder(String site, String path) {
    boolean toRet = false;
    PersistenceManagerService persistenceManagerService =
        _servicesManager.getService(PersistenceManagerService.class);
    String rootPath = SITE_REPO_ROOT_PATTERN.replaceAll(SITE_REPLACEMENT_PATTERN, site);
    NodeRef nodeRef = persistenceManagerService.getNodeRef(rootPath, path);

    if (nodeRef != null) {
      FileInfo fileInfo = persistenceManagerService.getFileInfo(nodeRef);
      toRet = fileInfo.isFolder();
    }
    return toRet;
  }

  @Override
  public boolean environmentRepoExists(String site, String environment) {
    PersistenceManagerService persistenceManagerService =
        getServicesManager().getService(PersistenceManagerService.class);

    String envRepoPath = SITE_ENVIRONMENT_ROOT_PATTERN.replaceAll(SITE_REPLACEMENT_PATTERN, site);
    envRepoPath = envRepoPath.replaceAll(ENVIRONMENT_REPLACEMENT_PATTERN, environment);

    return persistenceManagerService.exists(envRepoPath);
  }

  @Override
  public void createEnvironmentRepo(String site, String environment) {
    createEnvRepository(site, environment);
  }

  @Override
  public String getLiveEnvironmentName(String site) {
    SiteService siteService = getServicesManager().getService(SiteService.class);
    return siteService.getLiveEnvironmentName(site);
  }

  @Override
  public Set<String> getAllPublishingEnvironments(String site) {
    SiteService siteService = _servicesManager.getService(SiteService.class);
    Map<String, PublishingChannelGroupConfigTO> groupConfigTOs =
        siteService.getPublishingChannelGroupConfigs(site);
    Set<String> environments = new HashSet<String>();
    if (groupConfigTOs != null && groupConfigTOs.size() > 0) {
      for (PublishingChannelGroupConfigTO groupConfigTO : groupConfigTOs.values()) {
        if (StringUtils.isNotEmpty(groupConfigTO.getName())) {
          environments.add(groupConfigTO.getName());
        }
      }
    }
    return environments;
  }

  @Override
  public void lockRepository() {
    GeneralLockService generalLockService =
        getServicesManager().getService(GeneralLockService.class);
    generalLockService.lock(GeneralLockService.MASTER_LOCK);
  }

  @Override
  public void unlockRepository() {
    GeneralLockService generalLockService =
        getServicesManager().getService(GeneralLockService.class);
    generalLockService.unlock(GeneralLockService.MASTER_LOCK);
  }

  @Override
  public void lockItem(final String site, final String path) {
    GeneralLockService generalLockService =
        getServicesManager().getService(GeneralLockService.class);
    PersistenceManagerService persistenceManagerService =
        _servicesManager.getService(PersistenceManagerService.class);
    String rootPath = SITE_REPO_ROOT_PATTERN.replaceAll(SITE_REPLACEMENT_PATTERN, site);
    NodeRef nodeRef = persistenceManagerService.getNodeRef(rootPath, path);
    if (nodeRef != null) {
      generalLockService.lock(nodeRef.getId());
    }
  }

  @Override
  public void unLockItem(final String site, final String path) {
    GeneralLockService generalLockService =
        getServicesManager().getService(GeneralLockService.class);
    PersistenceManagerService persistenceManagerService =
        _servicesManager.getService(PersistenceManagerService.class);
    String rootPath = SITE_REPO_ROOT_PATTERN.replaceAll(SITE_REPLACEMENT_PATTERN, site);
    NodeRef nodeRef = persistenceManagerService.getNodeRef(rootPath, path);
    if (nodeRef != null) {
      generalLockService.unlock(nodeRef.getId());
    }
  }

  /** dmContentService getter */
  public DmContentService getDmContentService() {
    return _dmContentService;
  }
  /** dmContentService setter */
  public void setDmContentService(DmContentService service) {
    _dmContentService = service;
  }

  public ServicesManager getServicesManager() {
    return _servicesManager;
  }

  public void setServicesManager(ServicesManager servicesManager) {
    this._servicesManager = servicesManager;
  }

  public org.alfresco.service.transaction.TransactionService getTransactionService() {
    return _transactionService;
  }

  public void setTransactionService(
      org.alfresco.service.transaction.TransactionService transactionService) {
    _transactionService = transactionService;
  }

  public DmFilterWrapper getDmFilterWrapper() {
    return _dmFilterWrapper;
  }

  public void setDmFilterWrapper(DmFilterWrapper dmFilterWrapper) {
    this._dmFilterWrapper = dmFilterWrapper;
  }

  protected ServicesManager _servicesManager;
  protected DmContentService _dmContentService;
  protected org.alfresco.service.transaction.TransactionService _transactionService;
  protected DmFilterWrapper _dmFilterWrapper;
}