const elementaPath = Java.type("gg.essential.elementa");

export const WindowScreen = elementaPath.WindowScreen;

export const GradientComponent = elementaPath.components.GradientComponent;
export const SVGComponent = elementaPath.components.SVGComponent;
export const ScrollComponent = elementaPath.components.ScrollComponent;
export const TreeGraphComponent = elementaPath.components.TreeGraphComponent;
export const TreeListComponent = elementaPath.components.TreeListComponent;
export const UIBlock = elementaPath.components.UIBlock;
export const UICircle = elementaPath.components.UICircle;
export const UIContainer = elementaPath.components.UIContainer;
export const UIImage = elementaPath.components.UIImage;
export const UIPoint = elementaPath.components.UIPoint;
export const UIRoundedRectangle = elementaPath.components.UIRoundedRectangle;
export const UIShape = elementaPath.components.UIShape;
export const UIText = elementaPath.components.UIText;
export const UIWrappedText = elementaPath.components.UIWrappedText;
export const Window = elementaPath.components.Window;

export const BlurHashImage = elementaPath.components.image.BlurHashImage;
export const CacheableImage = elementaPath.components.image.CacheableImage;
export const DefaultLoadingImage =
  elementaPath.components.image.DefaultLoadingImage;
export const FileImageCache = elementaPath.components.image.FileImageCache;
export const ImageCache = elementaPath.components.image.ImageCache;
export const ImageProvider = elementaPath.components.image.ImageProvider;
export const MSDFComponent = elementaPath.components.image.MSDFComponent;

export const UIMultilineTextInput =
  elementaPath.components.input.UIMultilineTextInput;
export const UIPasswordInput = elementaPath.components.input.UIPasswordInput;
export const UITextInput = elementaPath.components.input.UITextInput;

export const ArrowComponent = elementaPath.components.inspector.ArrowComponent;
export const InfoBlock = elementaPath.components.inspector.InfoBlock;
export const InfoBlockNode = elementaPath.components.inspector.InfoBlockNode;
export const Inspector = elementaPath.components.inspector.Inspector;
export const InspectorNode = elementaPath.components.inspector.InspectorNode;

export const PlotBounds = elementaPath.components.plot.Bounds;
export const LineType = elementaPath.components.plot.LineType;
export const PlotComponent = elementaPath.components.plot.PlotComponent;
export const PlotStyle = elementaPath.components.plot.PlotStyle;
export const PointType = elementaPath.components.plot.PointType;

export const AdditiveConstraint = elementaPath.constraints.AdditiveConstraint;
export const AspectConstraint = elementaPath.constraints.AspectConstraint;
export const CenterConstraint = elementaPath.constraints.CenterConstraint;
export const ChildBasedSizeConstraint =
  elementaPath.constraints.ChildBasedSizeConstraint;
export const ChildBasedMaxSizeConstraint =
  elementaPath.constraints.ChildBasedMaxSizeConstraint;
export const ChildBasedRangeConstraint =
  elementaPath.constraints.ChildBasedRangeConstraint;
export const CoerceAtLeastConstraint =
  elementaPath.constraints.CoerceAtLeastConstraint;
export const CoerceAtMostConstraint =
  elementaPath.constraints.CoerceAtMostConstraint;
export const CoerceInConstraint = elementaPath.constraints.CoerceInConstraint;
export const ConstantColorConstraint =
  elementaPath.constraints.ConstantColorConstraint;
export const AlphaAspectColorConstraint =
  elementaPath.constraints.AlphaAspectColorConstraint;
export const RainbowColorConstraint =
  elementaPath.constraints.RainbowColorConstraint;
export const ConstraintType = elementaPath.constraints.ConstraintType;
export const CopyConstraintFloat = elementaPath.constraints.CopyConstraintFloat;
export const CopyConstraintColor = elementaPath.constraints.CopyConstraintColor;
export const CramSiblingConstraint =
  elementaPath.constraints.CramSiblingConstraint;
export const FillConstraint = elementaPath.constraints.FillConstraint;
export const ImageAspectConstraint =
  elementaPath.constraints.ImageAspectConstraint;
export const InheritedColorConstraint =
  elementaPath.constraints.InheritedColorConstraint;
export const MaxConstraint = elementaPath.constraints.MaxConstraint;
export const MaxImageConstraint = elementaPath.constraints.MaxImageConstraint;
export const MinConstraint = elementaPath.constraints.MinConstraint;
export const MousePositionConstraint =
  elementaPath.constraints.MousePositionConstraint;
export const PaddingConstraint = elementaPath.constraints.PaddingConstraint;
export const PixelConstraint = elementaPath.constraints.PixelConstraint;
export const RelativeConstraint = elementaPath.constraints.RelativeConstraint;
export const RelativeWindowConstraint =
  elementaPath.constraints.RelativeWindowConstraint;
export const RoundingConstraint = elementaPath.constraints.RoundingConstraint;
export const ScaleConstraint = elementaPath.constraints.ScaleConstraint;
export const ScaledTextConstraint =
  elementaPath.constraints.ScaledTextConstraint;
export const SiblingConstraint = elementaPath.constraints.SiblingConstraint;
export const SubtractiveConstraint =
  elementaPath.constraints.SubtractiveConstraint;
export const TextAspectConstraint =
  elementaPath.constraints.TextAspectConstraint;

export const AnimatingConstraints =
  elementaPath.constraints.animation.AnimatingConstraints;
export const XAnimationComponent =
  elementaPath.constraints.animation.XAnimationComponent;
export const YAnimationComponent =
  elementaPath.constraints.animation.YAnimationComponent;
export const RadiusAnimationComponent =
  elementaPath.constraints.animation.RadiusAnimationComponent;
export const WidthAnimationComponent =
  elementaPath.constraints.animation.WidthAnimationComponent;
export const HeightAnimationComponent =
  elementaPath.constraints.animation.HeightAnimationComponent;
export const ColorAnimationComponent =
  elementaPath.constraints.animation.ColorAnimationComponent;
export const FloatFieldAnimationComponent =
  elementaPath.constraints.animation.FloatFieldAnimationComponent;
export const DoubleFieldAnimationComponent =
  elementaPath.constraints.animation.DoubleFieldAnimationComponent;
export const IntFieldAnimationComponent =
  elementaPath.constraints.animation.IntFieldAnimationComponent;
export const LongFieldAnimationComponent =
  elementaPath.constraints.animation.LongFieldAnimationComponent;
export const ColorFieldAnimationComponent =
  elementaPath.constraints.animation.ColorFieldAnimationComponent;
export const Animations = elementaPath.constraints.animation.Animations;

export const ConstraintResolutionGui =
  elementaPath.constraints.resolution.ConstraintResolutionGui;
export const ConstraintResolver =
  elementaPath.constraints.resolution.ConstraintResolver;
export const ConstraintVisitor =
  elementaPath.constraints.resolution.ConstraintVisitor;
export const DirectedAcyclicGraph =
  elementaPath.constraints.resolution.DirectedAcyclicGraph;
export const ResolverNode = elementaPath.constraints.resolution.ResolverNode;

export const OutlineEffect = elementaPath.effects.OutlineEffect;
export const RecursiveFadeEffect = elementaPath.effects.RecursiveFadeEffect;
export const ScissorEffect = elementaPath.effects.ScissorEffect;
export const StencilEffect = elementaPath.effects.StencilEffect;

export const UIClickEvent = elementaPath.events.UIClickEvent;
export const UIScrollEvent = elementaPath.events.UIScrollEvent;

export const DefaultFonts = elementaPath.font.DefaultFonts.INSTANCE;
export const ElementaFonts = elementaPath.font.ElementaFonts.INSTANCE;
export const FontRenderer = elementaPath.font.FontRenderer;

export const DrawState = elementaPath.markdown.DrawState;
export const MarkdownComponent = elementaPath.markdown.MarkdownComponent;
export const MarkdownConfig = elementaPath.markdown.MarkdownConfig;
export const HeaderConfig = elementaPath.markdown.HeaderConfig;
export const HeaderLevelConfig = elementaPath.markdown.HeaderLevelConfig;
export const ListConfig = elementaPath.markdown.ListConfig;
export const ParagraphConfig = elementaPath.markdown.ParagraphConfig;
export const TextConfig = elementaPath.markdown.TextConfig;
export const InlineCodeConfig = elementaPath.markdown.InlineCodeConfig;
export const CodeBlockConfig = elementaPath.markdown.CodeBlockConfig;
export const URLConfig = elementaPath.markdown.URLConfig;
export const BlockquoteConfig = elementaPath.markdown.BlockquoteConfig;
export const MarkdownRenderer = elementaPath.markdown.MarkdownRenderer;

export const PathParser = elementaPath.svg.PathParser;
export const SVGParser = elementaPath.svg.SVGParser.INSTANCE;

export const ExpandFromTransition =
  elementaPath.transitions.ExpandFromTransition.INSTANCE;
export const RecursiveFadeInTransition =
  elementaPath.transitions.RecursiveFadeInTransition;
export const RecursiveFadeOutTransition =
  elementaPath.transitions.RecursiveFadeOutTransition;
export const ShrinkToTransition =
  elementaPath.transitions.ShrinkToTransition.INSTANCE;
export const ShrinkTransition = elementaPath.transitions.ShrinkTransition;
export const SlideFromTransition =
  elementaPath.transitions.SlideFromTransition.INSTANCE;
export const SlideToTransition =
  elementaPath.transitions.SlideToTransition.INSTANCE;

Number.prototype.pixels = function (
  alignedOpposite = false,
  alignedOutside = false
) {
  return new PixelConstraint(this, alignedOpposite, alignedOutside);
};

Number.prototype.pixel = function (
  alignedOpposite = false,
  alignedOutside = false
) {
  return this.pixels(alignedOpposite, alignedOutside);
};

Number.prototype.percent = function () {
  return new RelativeConstraint(this / 100);
};

Number.prototype.percentOfWindow = function () {
  return new RelativeWindowConstraint(this / 100);
};

String.prototype.width = function (
  textScale = 1,
  fontProvider = DefaultFonts.VANILLA_FONT_RENDERER
) {
  return fontProvider.getStringWidth(this, 10) * textScale;
};

/**
 * @typedef {any} UIComponent
 * @typedef {any} AnimatingConstraints
 */

/**
 * Wrapper around [UIComponent.makeAnimation] and [UIComponent.animateTo].
 *
 * @param {UIComponent} component the component to add the animation to
 * @param {(animation: AnimatingConstraints) => void} callback
 * @returns {UIComponent} the original component
 */
export const animate = (component, callback) => {
  const anim = component.makeAnimation();
  callback(anim);
  component.animateTo(anim);

  return component;
};
