var toPoint = function(p) {
  if(p instanceof Point)
    return p.clone();
  return new Point(p.x, p.y)
};

var FaceMarks = function(landmarks) {
  var jaw = landmarks.getJawOutline(),
    nose = landmarks.getNose(),
    mouth = landmarks.getMouth(),
    leftBrow = landmarks.getLeftEyeBrow(),
    rightBrow = landmarks.getRightEyeBrow(),

    leftEye = landmarks.getLeftEye(),
    rightEye = landmarks.getRightEye();


  var marks = this.marks = {
    cheek: {
      left: {},
      right: {}
    },
    lips: {
      top: {},
      bottom: {}
    },
    brows: {
      left: {}, right: {}
    },
    eyes: {
      left: {}, right: {}
    },
    skin: {
      top: {},
      underEye: {left: [], right: []},
      underNose: {left: [], right: []},
      chin: []
    }
  };

  // CHEEKS
  marks.cheek.left = this.cheek(nose[3], toPoint(jaw[0]).middle(toPoint(jaw[1])), mouth[0]);
  marks.cheek.right = this.cheek(nose[3], toPoint(jaw[15]).middle(toPoint(jaw[16])), mouth[6]);

  // LIPS
  marks.lips.top = this.lip(mouth[2], mouth[4], mouth[13], mouth[15], true);
  marks.lips.bottom = this.lip(mouth[10], mouth[8], mouth[19], mouth[17], true);

  // EYES
  marks.eyes.left = this.eye(leftBrow[0], leftBrow[3], leftEye[0], leftEye[2], leftEye[3], leftEye[4]);
  marks.eyes.right = this.eye(rightBrow[4], rightBrow[1], rightEye[3], rightEye[1], rightEye[0], rightEye[5]);

  // SKIN
  marks.skin.top = this.topSkin(leftBrow[2], rightBrow[2], nose[0]);
  marks.skin.underEye = this.underEyeSkin(nose[2], marks.eyes, marks.cheek );
  marks.skin.underNose = this.undeNoseSkin(mouth[2], mouth[4], mouth[1], mouth[5], marks.eyes, marks.cheek );
  marks.skin.chin = this.chinSkin(mouth[11], mouth[7], jaw[8] );
};

FaceMarks.prototype = {
  chinSkin: function(m1, m2, j1) {
    m1 = toPoint(m1);
    m2 = toPoint(m2);

    j1 = toPoint(j1);

    var base = [
      m1.lerp(j1,2/5),
      m2.lerp(j1,2/5),
      m1.lerp(m2,0.5).lerp(j1, 5/6),
    ];

    return [base[0].lerp(base[1], 3/2), base[1].lerp(base[0], 3/2), base[2]]
  },
  undeNoseSkin: function(m1, m2, m3, m4, eye, cheek) {
    m1 = toPoint(m1);
    m2 = toPoint(m2);
    m3 = toPoint(m3);
    m4 = toPoint(m4);

    return {
      left: [
        m1.lerp(cheek.left.bonus2[1], 2/3),
        m1.lerp(cheek.left.bonus2[1], 1/3),
        cheek.left.bonus2[2].lerp(m3, 0.5)
      ],
      right: [
        m2.lerp(cheek.right.bonus2[1], 2/3),
        m2.lerp(cheek.right.bonus2[1], 1/3),
        cheek.right.bonus2[2].lerp(m4, 0.5)
      ],
    }
  },

  underEyeSkin: function(n1, eye, cheek) {
    n1 = toPoint(n1);

    var p0 = n1.lerp(eye.left.t3[1],0.5);

    var p1 = n1.lerp(eye.right.t3[1],0.5);
    return {
      left: [
        p0,
        p0.lerp(cheek.left.bonus2[1], 0.5),
        p0.lerp(cheek.left.bonus2[1], 0.5).add(
          cheek.left.bonus2[1].subClone(cheek.left.bonus2[2]).mul(-0.5)
        )
      ],
      right: [
        p1,
        p1.lerp(cheek.right.bonus2[1], 0.5),
        p1.lerp(cheek.right.bonus2[1], 0.5).add(
          cheek.right.bonus2[1].subClone(cheek.right.bonus2[2]).mul(-0.5)
        )
      ],
    }
  },
  topSkin: function(b1,b2, n1) {
    b1 = toPoint(b1);
    b2 = toPoint(b2);
    n1 = toPoint(n1);

    var center = b1.middle(b2);
    var upVector = n1.subClone(center);

    return {
      left: [
        b1.subClone(upVector.mulClone(2/3)),
        center.subClone(upVector.mulClone(17/30)).add(b1.lerp(b2,1).normalize().mul(-2)),
        center

      ],
      right: [
        b2.subClone(upVector.mulClone(2/3)),
        center.subClone(upVector.mulClone(17/30)).add(b1.lerp(b2,1).normalize().mul(2)),
        center
      ],
    }
  },
  eye: function(b1,b2, e1,e2,e3,e4) {
    b1 = toPoint(b1),
    b2 = toPoint(b2),
    e1 = toPoint(e1),
    e2 = toPoint(e2),
    e3 = toPoint(e3),
    e4 = toPoint(e4);
    var t1, t2, t3, t4;
    var eyes = {
      t1: t1 = [
        b2.lerp(e2, 2/3),
        b1.lerp(e1, 2/3),
        b1.lerp(e1, 1/3)
      ],
      t2: t2 = [
        b1.lerp(e1, 0.95/3),
        b1.lerp(b2, 0.5).lerp(e1, 1/3),
        b1.lerp(b2, 0.5).lerp(e1, 1.4/3)
      ],
      t3: t3 = [
        e2.lerp(e3, 2),
        e2.lerp(e4, 1.65),
        e2.lerp(e4, 2.45)
      ],
      t4: t4 = [
        e2.lerp(e4, 1.65),
        e2.lerp(e4, 2.45),
        b2.lerp(e1, 1.5)
      ]
    };
    eyes.t5 = [
      t1[1].lerp(t1[0],4/5),
      t1[2].lerp(t1[0],5/4),
      e2.lerp(e4, 1.65).lerp(
      e2.lerp(e3, 2), 1.3)
      //t3[0].//lerp(t1[0],1/4)
    ];

    eyes.t6 = [
      t1[1].lerp(t1[2],1/2),
      t1[0].lerp(t1[1],3/2),
      t4[2].lerp(t1[1],2/3)
    ];
    var p = t3[0].lerp(t3[2], 0.5);
    eyes.t7 = [
      p,
      t3[1].lerp(p, 2),
      t3[1].lerp(t3[0], 1.4)
    ];
    return eyes;

  },
  cheek: function(nose, jaw, mouthSide) {
    var p1 = toPoint(nose),
      p2 = toPoint(jaw),
      p3 = toPoint(mouthSide), originP3 = p3.clone();

    p3.add(p2.subClone(p3).mul(1/2));
    var v1 = p2.subClone(p1);
    p1.add(v1.mulClone(1/2));
    p2.sub(v1.mul(1/3));

    var cheek = [p1,p2,p3];

    var vx = cheek[0].subClone(cheek[1]),
      vy = cheek[1].subClone(cheek[2]);

    var bonusArea = [
      cheek[1].subClone(vx.mulClone(1/2)),
      cheek[1].subClone(vx.normalize().mul(3))
    ];
    bonusArea.push(bonusArea[1].subClone(vy.mul(1.4)));

    bonusArea[0].sub(vy.mulClone(1/2));
    bonusArea[1].sub(vy.mulClone(1/5));


    var bonusArea2 = [
      bonusArea[2].clone(),
      cheek[0].clone()
    ];
    var middle = bonusArea2[0].middle(bonusArea2[1]),
      toMouthVector = originP3.subClone(middle);

    bonusArea2.push(middle.add(toMouthVector.mul(1/3)));

    toMouthVector.normalize().mul(2);

    bonusArea2[0].add(toMouthVector);
    bonusArea2[1].add(toMouthVector);

    return {base: cheek, bonus1: bonusArea, bonus2: bonusArea2};
  },
  lip: function(p1,p2,p3,p4, isTop) { // rectangular zone
    p1 = toPoint(p1); p2 = toPoint(p2); p3 = toPoint(p3); p4 = toPoint(p4);
    
    var lipVertical = p3.middle(p4).sub(p1.middle(p2)),
      lipHorizontal = toPoint(p2).sub(toPoint(p1)),
      lipDeltaX = lipHorizontal.clone().normalize().mul(3);

    var lips = [];
    lips.push([
      toPoint(p1).add(lipVertical.mulClone(1/3)),
      toPoint(p2).add(lipVertical.mulClone(1/3)),
      toPoint(p3).sub(lipVertical.mulClone(1/5))
    ]);
    lips.push([
      toPoint(p2).add(lipVertical.mulClone(1/3)).add(lipDeltaX),
      toPoint(p4).sub(lipVertical.mulClone(1/5)).add(lipDeltaX),
      toPoint(p3).sub(lipVertical.mulClone(1/5)).add(lipDeltaX)
    ]);


    lips.push( [
      lips[ 0 ][ isTop?2:0 ].subClone( lipHorizontal.mulClone( 1 / 2 ) ),
      lips[ 0 ][ 0 ].subClone( lipDeltaX ),
      lips[ 0 ][ 2 ].subClone( lipDeltaX ),
    ] );

    lips.push( [
      lips[ 1 ][ isTop?1:0 ].addClone( lipHorizontal.mulClone( 1 / 2 ) ),
      lips[ 1 ][ 1 ].addClone( lipDeltaX ),
      lips[ 1 ][ 0 ].addClone( lipDeltaX ),
    ] );

    return lips;
  }
};