﻿namespace Oni.Dae
{
    internal class Visitor
    {
        public virtual void VisitScene(Scene scene)
        {
            foreach (var node in scene.Nodes)
                VisitNode(node);
        }

        public virtual void VisitNode(Node node)
        {
            foreach (var transform in node.Transforms)
                VisitTransform(transform);

            foreach (var instance in node.Instances)
            {
                if (instance is GeometryInstance)
                    VisitGeometryInstance((GeometryInstance)instance);
                else if (instance is LightInstance)
                    VisitLightInstance((LightInstance)instance);
                else if (instance is CameraInstance)
                    VisitCameraInstance((CameraInstance)instance);
            }

            foreach (var child in node.Nodes)
                VisitNode(child);
        }

        public virtual void VisitGeometryInstance(GeometryInstance instance)
        {
            foreach (var materialInstance in instance.Materials)
                VisitMaterialInstance(materialInstance);

            VisitGeometry(instance.Target);
        }

        public virtual void VisitGeometry(Geometry geometry)
        {
            foreach (var input in geometry.Vertices)
                VisitInput(input);

            foreach (var primitives in geometry.Primitives)
                VisitMeshPrimitives(primitives);
        }

        public virtual void VisitMeshPrimitives(MeshPrimitives primitives)
        {
            foreach (var input in primitives.Inputs)
                VisitInput(input);
        }

        public virtual void VisitMaterialInstance(MaterialInstance instance)
        {
            VisitMaterial(instance.Target);
        }

        public virtual void VisitMaterial(Material material)
        {
            VisitEffect(material.Effect);
        }

        public virtual void VisitLightInstance(LightInstance instance)
        {
            VisitLight(instance.Target);
        }

        public virtual void VisitLight(Light light)
        {
        }

        public virtual void VisitCameraInstance(CameraInstance instance)
        {
            VisitCamera(instance.Target);
        }

        public virtual void VisitCamera(Camera camera)
        {
        }

        public virtual void VisitTransform(Transform transform)
        {
            if (transform.HasAnimations)
            {
                foreach (var sampler in transform.Animations.Where(s => s != null))
                    VisitSampler(sampler);
            }
        }

        public virtual void VisitSampler(Sampler sampler)
        {
            foreach (var input in sampler.Inputs)
                VisitInput(input);
        }

        public virtual void VisitEffect(Effect effect)
        {
            foreach (var parameter in effect.Parameters)
                VisitEffectParameter(parameter);

            VisitEffectParameter(effect.Ambient);
            VisitEffectParameter(effect.Diffuse);
            VisitEffectParameter(effect.Emission);
            VisitEffectParameter(effect.IndexOfRefraction);
            VisitEffectParameter(effect.Reflective);
            VisitEffectParameter(effect.Shininess);
            VisitEffectParameter(effect.Specular);
            VisitEffectParameter(effect.Transparency);
            VisitEffectParameter(effect.Transparent);
        }

        public virtual void VisitEffectParameter(EffectParameter parameter)
        {
            if (parameter.Value is EffectTexture)
                VisitEffectTexture((EffectTexture)parameter.Value);
        }

        public virtual void VisitEffectTexture(EffectTexture texture)
        {
            VisitEffectSampler(texture.Sampler);
        }

        public virtual void VisitEffectSampler(EffectSampler sampler)
        {
            VisitEffectSurface(sampler.Surface);
        }

        public virtual void VisitEffectSurface(EffectSurface surface)
        {
            VisitImage(surface.InitFrom);
        }

        public virtual void VisitInput(Input input)
        {
            VisitSource(input.Source);
        }

        public virtual void VisitSource(Source source)
        {
        }

        public virtual void VisitImage(Image image)
        {
        }
    }
}
