/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%            AAA   RRRR   TTTTT  IIIII  FFFFF   AAA    CCCC  TTTTT            %
%           A   A  R   R    T      I    F      A   A  C        T              %
%           AAAAA  RRRRR    T      I    FFF    AAAAA  C        T              %
%           A   A  R R      T      I    F      A   A  C        T              %
%           A   A  R  R     T    IIIII  F      A   A  CCCCC    T              %
%                                                                             %
%                                                                             %
%                         MagickCore Artifact Methods                         %
%                                                                             %
%                              Software Design                                %
%                                   Cristy                                    %
%                                 March 2000                                  %
%                                                                             %
%                                                                             %
%  Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization      %
%  dedicated to making software imaging solutions freely available.           %
%                                                                             %
%  You may not use this file except in compliance with the License.  You may  %
%  obtain a copy of the License at                                            %
%                                                                             %
%    https://imagemagick.org/script/license.php                               %
%                                                                             %
%  Unless required by applicable law or agreed to in writing, software        %
%  distributed under the License is distributed on an "AS IS" BASIS,          %
%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
%  See the License for the specific language governing permissions and        %
%  limitations under the License.                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%
%
*/

/*
  Include declarations.
*/
#include "MagickCore/studio.h"
#include "MagickCore/artifact.h"
#include "MagickCore/cache.h"
#include "MagickCore/color.h"
#include "MagickCore/compare.h"
#include "MagickCore/constitute.h"
#include "MagickCore/draw.h"
#include "MagickCore/effect.h"
#include "MagickCore/exception.h"
#include "MagickCore/exception-private.h"
#include "MagickCore/fx.h"
#include "MagickCore/fx-private.h"
#include "MagickCore/gem.h"
#include "MagickCore/geometry.h"
#include "MagickCore/image.h"
#include "MagickCore/layer.h"
#include "MagickCore/list.h"
#include "MagickCore/memory_.h"
#include "MagickCore/monitor.h"
#include "MagickCore/montage.h"
#include "MagickCore/option.h"
#include "MagickCore/profile.h"
#include "MagickCore/quantum.h"
#include "MagickCore/resource_.h"
#include "MagickCore/splay-tree.h"
#include "MagickCore/signature-private.h"
#include "MagickCore/statistic.h"
#include "MagickCore/string_.h"
#include "MagickCore/token.h"
#include "MagickCore/utility.h"
#include "MagickCore/xml-tree.h"

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   C l o n e I m a g e A r t i f a c t s                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  CloneImageArtifacts() clones all image artifacts to another image.
%
%  This will not delete any existing artifacts that may be present!
%
%  The format of the CloneImageArtifacts method is:
%
%      MagickBooleanType CloneImageArtifacts(Image *image,
%        const Image *clone_image)
%
%  A description of each parameter follows:
%
%    o image: the image, to recieve the cloned artifacts.
%
%    o clone_image: the source image for artifacts to clone.
%
*/
MagickExport MagickBooleanType CloneImageArtifacts(Image *image,
  const Image *clone_image)
{
  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  assert(clone_image != (const Image *) NULL);
  assert(clone_image->signature == MagickCoreSignature);
  if (clone_image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
      clone_image->filename);
  if (clone_image->artifacts != (void *) NULL)
    {
      if (image->artifacts != (void *) NULL)
        DestroyImageArtifacts(image);
      image->artifacts=CloneSplayTree((SplayTreeInfo *) clone_image->artifacts,
        (void *(*)(void *)) ConstantString,(void *(*)(void *)) ConstantString);
    }
  return(MagickTrue);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   D e f i n e I m a g e A r t i f a c t                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  DefineImageArtifact() associates an assignment string of the form
%  "key=value" with per-image artifact. It is equivelent to
%  SetImageArtifact().
%
%  The format of the DefineImageArtifact method is:
%
%      MagickBooleanType DefineImageArtifact(Image *image,
%        const char *artifact)
%
%  A description of each parameter follows:
%
%    o image: the image.
%
%    o artifact: the image artifact.
%
*/
MagickExport MagickBooleanType DefineImageArtifact(Image *image,
  const char *artifact)
{
  char
    key[MagickPathExtent],
    value[MagickPathExtent];

  register char
    *p;

  assert(image != (Image *) NULL);
  assert(artifact != (const char *) NULL);
  (void) CopyMagickString(key,artifact,MagickPathExtent-1);
  for (p=key; *p != '\0'; p++)
    if (*p == '=')
      break;
  *value='\0';
  if (*p == '=')
    (void) CopyMagickString(value,p+1,MagickPathExtent);
  *p='\0';
  return(SetImageArtifact(image,key,value));
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   D e l e t e I m a g e A r t i f a c t                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  DeleteImageArtifact() deletes an image artifact.
%
%  The format of the DeleteImageArtifact method is:
%
%      MagickBooleanType DeleteImageArtifact(Image *image,const char *artifact)
%
%  A description of each parameter follows:
%
%    o image: the image.
%
%    o artifact: the image artifact.
%
*/
MagickExport MagickBooleanType DeleteImageArtifact(Image *image,
  const char *artifact)
{
  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  if (image->artifacts == (void *) NULL)
    return(MagickFalse);
  return(DeleteNodeFromSplayTree((SplayTreeInfo *) image->artifacts,artifact));
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   D e s t r o y I m a g e A r t i f a c t s                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  DestroyImageArtifacts() destroys all artifacts and associated memory
%  attached to the given image.
%
%  The format of the DestroyImageArtifacts method is:
%
%      void DestroyImageArtifacts(Image *image)
%
%  A description of each parameter follows:
%
%    o image: the image.
%
*/
MagickExport void DestroyImageArtifacts(Image *image)
{
  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  if (image->artifacts != (void *) NULL)
    image->artifacts=(void *) DestroySplayTree((SplayTreeInfo *)
      image->artifacts);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   G e t I m a g e A r t i f a c t                                           %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  GetImageArtifact() gets a value associated with an image artifact.
%  If the requested artifact is NULL return the first artifact, to
%  prepare to iterate over all artifacts.
%
%  The returned string is a constant string in the tree and should NOT be
%  freed by the caller.
%
%  The format of the GetImageArtifact method is:
%
%      const char *GetImageArtifact(const Image *image,const char *key)
%
%  A description of each parameter follows:
%
%    o image: the image.
%
%    o key: the key.
%
*/
MagickExport const char *GetImageArtifact(const Image *image,
  const char *artifact)
{
  register const char
    *p;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  p=(const char *) NULL;
  if (image->artifacts != (void *) NULL)
    {
      if (artifact == (const char *) NULL)
        return((const char *) GetRootValueFromSplayTree((SplayTreeInfo *)
          image->artifacts));
      p=(const char *) GetValueFromSplayTree((SplayTreeInfo *) image->artifacts,
        artifact);
      if (p != (const char *) NULL)
        return(p);
    }
  if ((image->image_info != (ImageInfo *) NULL) &&
      (image->image_info->options != (void *) NULL))
    p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
      image->image_info->options,artifact);
  return(p);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   G e t N e x t I m a g e A r t i f a c t                                   %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  GetNextImageArtifact() gets the next image artifact value.
%
%  The format of the GetNextImageArtifact method is:
%
%      char *GetNextImageArtifact(const Image *image)
%
%  A description of each parameter follows:
%
%    o image: the image.
%
*/
MagickExport const char *GetNextImageArtifact(const Image *image)
{
  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  if (image->artifacts == (void *) NULL)
    return((const char *) NULL);
  return((const char *) GetNextKeyInSplayTree(
   (SplayTreeInfo *) image->artifacts));
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   R e m o v e I m a g e A r t i f a c t                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  RemoveImageArtifact() removes an artifact from the image and returns its
%  value.
%
%  In this case the ConstantString() value returned should be freed by the
%  caller when finished.
%
%  The format of the RemoveImageArtifact method is:
%
%      char *RemoveImageArtifact(Image *image,const char *artifact)
%
%  A description of each parameter follows:
%
%    o image: the image.
%
%    o artifact: the image artifact.
%
*/
MagickExport char *RemoveImageArtifact(Image *image,const char *artifact)
{
  char
    *value;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  if (image->artifacts == (void *) NULL)
    return((char *) NULL);
  value=(char *) RemoveNodeFromSplayTree((SplayTreeInfo *) image->artifacts,
    artifact);
  return(value);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   R e s e t I m a g e A r t i f a c t I t e r a t o r                       %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  ResetImageArtifactIterator() resets the image artifact iterator.  Use it
%  in conjunction with GetNextImageArtifact() to iterate over all the values
%  associated with an image artifact.
%
%  Alternatively you can use GetImageArtifact() with a NULL artifact field to
%  reset the iterator and return the first artifact.
%
%  The format of the ResetImageArtifactIterator method is:
%
%      ResetImageArtifactIterator(Image *image)
%
%  A description of each parameter follows:
%
%    o image: the image.
%
*/
MagickExport void ResetImageArtifactIterator(const Image *image)
{
  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  if (image->artifacts == (void *) NULL)
    return;
  ResetSplayTreeIterator((SplayTreeInfo *) image->artifacts);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   S e t I m a g e A r t i f a c t                                           %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  SetImageArtifact() associates makes a copy of the given string arguments
%  and inserts it into the artifact tree of the given image.
%
%  The format of the SetImageArtifact method is:
%
%      MagickBooleanType SetImageArtifact(Image *image,const char *artifact,
%        const char *value)
%
%  A description of each parameter follows:
%
%    o image: the image.
%
%    o artifact: the image artifact key.
%
%    o value: the image artifact value.
%
*/
MagickExport MagickBooleanType SetImageArtifact(Image *image,
  const char *artifact,const char *value)
{
  MagickBooleanType
    status;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  /*
    Create tree if needed - specify how key,values are to be freed.
  */
  if (image->artifacts == (void *) NULL)
    image->artifacts=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
      RelinquishMagickMemory);
  /*
    Delete artifact if NULL --  empty string values are valid!,
  */
  if (value == (const char *) NULL)
    return(DeleteImageArtifact(image,artifact));
  /*
    Add artifact to splay-tree.
  */
  status=AddValueToSplayTree((SplayTreeInfo *) image->artifacts,
    ConstantString(artifact),ConstantString(value));
  return(status);
}
