// Copyright Contributors to the Open Shading Language project.
// SPDX-License-Identifier: BSD-3-Clause
// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage


#ifdef ORDER_1
  #include "a_fcn.h"
  #include "b_nci.h"
  #include "c_vpi.h"

  #include "a_ivp.h"
  #include "b_vpf.h"
  #include "c_cnf.h"
#else
  #include "a_ivp.h"
  #include "b_vpf.h"
  #include "c_cnf.h"

  #include "a_fcn.h"
  #include "b_nci.h"
  #include "c_vpi.h"
#endif

int intval() { return 0; }
float floatval() { return 0.0; }


normal testD(normal a, float b, float c) {
    printf("testD normal\n");
    return normal(0);
}
color testD(color a, float b, float c) {
    printf("testD color\n");
    return color(1);
}
vector testD(vector a, float b, float c) {
    printf("testD vector\n");
    return vector(2);
}
point testD(point a, float b, float c) {
    printf("testD point\n");
    return point(3);
}
int testD(int a, float b, float c) {
    printf("testD int\n");
    return 4;
}
float testD(float a, float b, float c) {
    printf("testD float\n");
    return 5;
}

// This would break C++
int testD(int a, int b, float c) {
    printf("testD int2\n");
    return 4;
}

int testE(int a, float b, color s) {
    printf("testE color\n");
    return 4;
}
int testE(float a, int b, vector v) {
    printf("testE vector\n");
    return 4;
}

int   funcb() { printf("funcb.int\n");   return 1; }
float funcb() { printf("funcb.float\n"); return 2; }
color funcb() { printf("funcb.color\n"); return 3; }

struct A { float a; };

int    freturn() { printf("freturn.int\n"); return 1; }
point  freturn() { printf("freturn.point\n"); return 1; }
string freturn() { printf("freturn.string\n"); return ""; }
float  freturn() { printf("freturn.float\n"); return 1; }
color  freturn() { printf("freturn.color\n"); return 1; }
closure color  freturn() { printf("freturn.ccolor\n"); return diffuse(N); }
vector freturn() { printf("freturn.vector\n"); return 1; }
normal freturn() { printf("freturn.normal\n"); return 1; }
matrix freturn() { printf("freturn.matrix\n"); return 1; }
void   freturn() { printf("freturn.void\n"); }
A freturn() { printf("freturn.struct\n"); A a; return a; }

A ireturn() { printf("ireturn.struct\n"); A a; return a; }
closure color  ireturn() { printf("ireturn.ccolor\n"); return diffuse(N); }
color  ireturn() { printf("ireturn.color\n"); return 1; }
point  ireturn() { printf("ireturn.point\n"); return 1; }
string ireturn() { printf("ireturn.string\n"); return ""; }
int    ireturn() { printf("ireturn.int\n"); return 1; }
vector ireturn() { printf("ireturn.vector\n"); return 1; }
normal ireturn() { printf("ireturn.normal\n"); return 1; }
void   ireturn() { printf("ireturn.void\n"); }
matrix ireturn() { printf("ireturn.matrix\n"); return 1; }

vector creturn() { printf("creturn.vector\n"); return 1; }
normal creturn() { printf("creturn.normal\n"); return 1; }
void   creturn() { printf("creturn.void\n"); }
A creturn() { printf("creturn.struct\n"); A a; return a; }
point  creturn() { printf("creturn.point\n"); return 1; }
color  creturn() { printf("creturn.color\n"); return 1; }
string creturn() { printf("creturn.string\n"); return ""; }
matrix creturn() { printf("creturn.matrix\n"); return 1; }
closure color  creturn() { printf("creturn.ccolor\n"); return diffuse(N); }

point  vreturn() { printf("vreturn.point\n"); return 1; }
closure color  vreturn() { printf("vreturn.ccolor\n"); return diffuse(N); }
vector vreturn() { printf("vreturn.vector\n"); return 1; }
matrix vreturn() { printf("vreturn.matrix\n"); return 1; }
A vreturn() { printf("vreturn.struct\n"); A a; return a; }
void   vreturn() { printf("vreturn.void\n"); }
normal vreturn() { printf("vreturn.normal\n"); return 1; }
string vreturn() { printf("vreturn.string\n"); return ""; }

string preturn() { printf("preturn.string\n"); return ""; }
void   preturn() { printf("preturn.void\n"); }
normal preturn() { printf("preturn.normal\n"); return 1; }
closure color  preturn() { printf("preturn.ccolor\n"); return diffuse(N); }
matrix preturn() { printf("preturn.matrix\n"); return 1; }
A preturn() { printf("preturn.struct\n"); A a; return a; }
point  preturn() { printf("preturn.point\n"); return 1; }

matrix nreturn() { printf("nreturn.matrix\n"); return 1; }
A nreturn() { printf("nreturn.struct\n"); A a; return a; }
normal nreturn() { printf("nreturn.normal\n"); return 1; }
string nreturn() { printf("nreturn.string\n"); return ""; }
closure color  nreturn() { printf("nreturn.ccolor\n"); return diffuse(N); }
void   nreturn() { printf("nreturn.void\n"); }

void   mreturn() { printf("mreturn.void\n"); }
closure color  mreturn() { printf("mreturn.ccolor\n"); return diffuse(N); }
A mreturn() { printf("mreturn.struct\n"); A a; return a; }
matrix mreturn() { printf("mreturn.matrix\n"); return 1; }
string mreturn() { printf("mreturn.string\n"); return ""; }

A strreturn() { printf("strreturn.struct\n"); A a; return a; }
closure color  strreturn() { printf("strreturn.ccolor\n"); return diffuse(N); }
void   strreturn() { printf("strreturn.void\n"); }
string strreturn() { printf("strreturn.string\n"); return ""; }

closure color  ccreturn() { printf("ccreturn.ccolor\n"); return diffuse(N); }
void   ccreturn() { printf("ccreturn.void\n"); }
A ccreturn() { printf("ccreturn.struct\n"); A a; return a; }

A structreturn() { printf("structreturn.struct\n"); A a; return a; }
void structreturn() { printf("structreturn.void\n"); }

void structreturn1() { printf("structreturn1.void\n"); }
A structreturn1() { printf("structreturn1.struct\n"); A a; return a; }

struct B { float b; };

void aaa(A a, float b)  { printf("aaa.Afloat\n"); }
void aaa(B b, int c)    { printf("aaa.Bint\n"); }

void bbb(B b, int c)    { printf("bbb.Bint\n"); }
void bbb(A a, float b)  { printf("bbb.Afloat\n"); }

void ccc(A a, int b)    { printf("ccc.Aint\n"); }
void ccc(B b, float c)  { printf("ccc.Bfloat\n"); }

shader test ()
{
  {
      testA(intval(), 1.0, 1.0);
      testB(intval(), 1.0, 1.0);
      testC(intval(), 1.0, 1.0);
      testD(intval(), 1.0, 1.0);
      testA(intval(), 1, 1);
      testB(intval(), 1, 1);
      testC(intval(), 1, 1);
      testD(intval(), 1, 1);
      printf("\n");
  }

  {
      testA(floatval(), 1.0, 1.0);
      testB(floatval(), 1.0, 1.0);
      testC(floatval(), 1.0, 1.0);
      testD(floatval(), 1.0, 1.0);
      testA(floatval(), 1, 1);
      testB(floatval(), 1, 1);
      testC(floatval(), 1, 1);
      testD(floatval(), 1, 1);
      printf("\n");
  }

  {
    vector v0 = testD(intval(), 1.0, 1.0);
    vector v1 = testD(intval(), 1, 1);
    vector v2 = testD(floatval(), 1, 1);
    vector v3 = testD(vector(0), 1, 1);
    point  p0 = testD(intval(), 1.0, 1.0);
    point  p1 = testD(intval(), 1, 1);
    point  p2 = testD(floatval(), 1, 1);
    point  p3 = testD(point(0), 1, 1);
    color  c0 = testD(intval(), 1.0, 1.0);
    color  c1 = testD(intval(), 1, 1);
    color  c2 = testD(floatval(), 1, 1);
    color  c3 = testD(color(0), 1, 1);
    normal n0 = testD(intval(), 1.0, 1.0);
    normal n1 = testD(intval(), 1, 1);
    normal n2 = testD(floatval(), 1, 1);
    normal n3 = testD(normal(0), 1, 1);
    int    i0 = testD(intval(), 1.0, 1.0);
    int    i1 = testD(intval(), 1, 1);
    int    i2 = (int) testD(floatval(), 1, 1);
    float  f0 = testD(intval(), 1.0, 1.0);
    float  f1 = testD(intval(), 1, 1);
    float  f2 = testD(floatval(), 1, 1);
    printf("\n");
  }

  {
    testE(1, 1, color(0));
    testE(1, 1, vector(0));
    testE(1, 1, point(0));
    printf("\n");
  }

  {
    (color) funcb();
    (float) funcb();
    (int) funcb();
    printf("\n");
  }

  {
    freturn();
    ireturn();
    creturn();
    vreturn();
    preturn();
    nreturn();
    mreturn();
    strreturn();
    ccreturn();
    structreturn();
    structreturn1();
    printf("\n");
  }

  {
    aaa({1}, 1);
    aaa({1}, 1.0);
    bbb({1}, 1);
    bbb({1}, 1.0);
    ccc({1}, 1);
    ccc({1}, 1.0);
    printf("\n");
  }
}
