<!DOCTYPE html>
<html>

<head>
  <style>
    form {
      font: 400 16px/1.25 Consolas
    }
    
    input,
    output,
    button {
      display: inline-block;
      font: inherit
    }
    
    input {
      text-align: center;
    }
    
    img {
      display: block;
      margin: 0 auto;
      height: 250px;
      width: auto;
    }
  </style>
</head>

<body>
  <form id='poly' onsubmit='return false'>
    <fieldset>
      <legend>Regular Polygons</legend>
      <label> Sides: </label>
      <input id='qty' type='number' min='3' max='20'>
      <button id='btn'>GO</button>
    </fieldset>
    <fieldset id='view'></fieldset>
  </form>
  <script>
    /* Composite Objects */
    /*
    getType has the name() method which will convert props.sides into the 
    proper index of the types array to get the correct value for prop.type
    */
    const getType = (props, types) => ({
      name: () => {
        props.type = types[props.sides - 3];
      }
    });
    
    /*
    getLinx has the link() and image() methods props.type is used by the former 
    and props.sides and the dir array are used by the later to interpolate 
    strings into template literals that become urls for props.url and props.img.
    */
    const getLinx = (props, dir) => ({
      link: () => {
        props.url = `https://en.wikipedia.org/wiki/${props.type}`;
      },
      image: () => {
        switch (props.sides) {
          case 4:
            props.img = `https://upload.wikimedia.org/wikipedia/commons/3/3d/Six_Quadrilaterals.svg`;
            break;
          default:
            props.img = `https://upload.wikimedia.org/wikipedia/commons/${dir[props.sides - 3]}/Regular_polygon_${props.sides}_annotated.svg`;
            break;
        }
      }
    });
    /*
    polygon() function factory passes 2 parameters sides (Number) and tag 
    (String) props is the object that will have the three methods name(), link(), 
    and image() by concatenative inheritance using Object.assign().
    */
    const polygon = (sides, tag) => {
      const types = ["Triangle", "Quadrilateral", "Pentagon", "Hexagon", "Septagon", "Octogon", "Nonagon", "Decagon", "Undecagon", "Dodecagon", "Tridecagon", "Tetradecagon", "Pentadecagon", "Hexadecagon", "Heptadecagon", "Octadecagon", "Enneadecagon", "Icosagon"];
      const dir = ["e/eb", "3/3d", "0/01", "3/38", "7/75", "e/e5", "b/ba", "b/b9", "f/f8", "0/06", "a/a6", "e/e1", "d/d0", "e/e4", "c/c6", "d/d8", "1/18", "2/23"];
      let props = {
        tag: tag,
        sides: sides,
        type: '',
        url: '',
        img: '',
        desc: ''
      };
      return Object.assign(props, getType(props, types), getLinx(props, dir));
    };
    
    /* DOM Interface */
    /* 
    HTMLFormControlsCollection is a terse API that references tags by id or name
    */
    const poly = document.forms.poly;
    const qty = poly.qty;
    const view = poly.view;
    
    /*
    #btn is regustered to the click event. When triggered, the value of #qty 
    (.valueAsNumber) and the number of #view's chid elements (.childElementCount)
    become arguments for the function displayPoly().
    */
    poly.btn.addEventListener('click', (e) => {
      const vert = qty.valueAsNumber;
      const count = view.childElementCount;
      displayPoly(vert, count);
    });
    
    /* 
    displayPoly() passes the number from #qty and interpolates the number #view
    with a generic word to create a unique string to pass it to polygon() as the
    2nd argument. Next, the object creayed by polygon is returned and referenced
    as shape. shape's methods are invoked and then the new values are generated.
    The values of type, url, and img are interpolated into a string which is then
    rendered as HTML and prepended to #view.
    */
    const displayPoly = (number, index) => {
      let name = `shape${index}`;
      let shape = polygon(number, name);
      shape.name();
      shape.link();
      shape.image();
      let Type = shape.type;
      let Url = shape.url;
      let Img = shape.img;
      let item = `
  <figure id='${name}'>
    <figcaption title='${shape.sides} Sides'>${Type}</figcaption>
    <a href='${Url}'>
      <img src='${Img}'>
    </a>
  </figure>
  `;
      view.insertAdjacentHTML('afterbegin', item);
      return false;
    };
  </script>
</body>

</html>