title: Re-order an array's items based on several criteria
body: <p>Everybody I asked found this problem too challenging, hopefully there is someone here who can handle it.</p>
  
  <p>I have a program that generates business cards with inputs gave by a user (name, title, address etc.)</p>
  
  <p>I also have a page where users can configure how the info will look on the card: <a href="http://screencast.com/t/5j5CKAd0vi2l" rel="nofollow">http://screencast.com/t/5j5CKAd0vi2l</a></p>
  
  <p>Those configurations are used so that if some fields are empty, then other fields can move to take place of the empty field.</p>
  
  <p>How we should expect it to work:
  When a "field" is checked, it means that it can move. The arrow indicates the position where it should move. For example, name should move down, and title should move up. So if there is no name given in the input, and there is a title, then the title will go up and take the empty space of the name.</p>
  
  <p>When a field is not checked, it means that it cannot move, and a field cannot take its position (or step over it). So for example if there is a name, but there is no title, then the name would go down to take the title's spot but couldn't go down any further (even if "Office tel" was empty, so there would be a blank space on the business card).</p>
  
  <p>Using the same configurations example, if the user didn't input a mobile and email, but entered the last 2 fields (Address 1 and City, state, zip), then these last 2 fields would go up 2 fields, and take the places of mobile and email.</p>
  
  <p>Let's say my business card inputs are:</p>
  
  <pre><code>(checked, pointing down) Name: Dan
  (checked, pointing up) Title:
  (unchecked) Office tel:
  (checked, pointing up) Mobile tel:
  (checked, pointing up) Email: grwgwr@geffw.com
  (checked, pointing up) Address 1: 12 jal
  (checked, pointing up) City, state, zip: NYC, NY, 12345
  </code></pre>
  
  <p>The resulting renderValues array that I need would look like:</p>
  
  <pre><code>(
      [0] =&gt;
      [1] =&gt; Dan
      [2] =&gt; 
      [3] =&gt; grwgwr@geffw.com
      [4] =&gt; 12 jal
      [5] =&gt; NYC, NY, 12345
      [6] =&gt;  
  )
  </code></pre>
  
  <p>That's not what I'm getting with my code. You may not need it and it may confuse even more, but here's what I tried putting up so far:</p>
  
  <pre><code>foreach ($renderBlocksPropsByOrder as $blockID =&gt; $field) {
      $direction = $field['blankSensitivityDirection'];
  
      // note: if a field is not blank sensitive, it is locked
  
      if (trim($renderValues[$blockID]) == '' &amp;&amp; $field['isBlankSensitive'] == '1') {
          // if ($renderBlocksPropsByOrder[$blockID + 1])
          // the field(s) around this field can take its position
          // ??? if the field above is pointing down and the field below is pointing up, give priority to the field down ???
      } else if (trim($renderValues[$blockID]) == '' &amp;&amp; $field['isBlankSensitive'] == '0') {
          // fields above this field cannot go down past it even if it's empty, but they can all go down until they reach it
          // fields below this field cannot go up past it even if it's empty, but they can all go up until they reach it
          // this field will be a "blank" space field
      } else if (trim($renderValues[$blockID]) != '' &amp;&amp; $field['isBlankSensitive'] == '0') {
          // similar as the above case, except this field won't be a blank space
      } else if (trim($renderValues[$blockID]) != '' &amp;&amp; $field['isBlankSensitive'] == '1') {
          // this field should move if it can
          if ($direction === 'down') {
              // check fields below it to move it to the lowest available spot
              // (fields below have a higher index)
              for ($i = $blockID + 1; $i &lt; $numBlocks; $i++) {
                  if (trim($renderValues[$i]) != '') {
                      // prevent stepping over a field that has a value
                      break;
                  }
                  if (trim($renderValues[$i]) == '' &amp;&amp; $renderBlocksPropsByOrder[$i]['isBlankSensitive'] == '1') {
                      $renderValues[$i] = $renderValues[$blockID];
                      $renderValues[$blockID] = ' ';
                      break;
                  }
              }
          } else if ($direction === 'up') {
              // check fields above it to move it to the highest available spot
              // (fields above have a lower index)
              for ($i = $blockID - 1; $i &gt;= 0; $i--) {
                  if (trim($renderValues[$i]) != '') {
                      // prevent stepping over a field that has a value
                      break;
                  }
                  if (trim($renderValues[$i]) == '' &amp;&amp; $renderBlocksPropsByOrder[$i]['isBlankSensitive'] == '1') {
                      $renderValues[$i] = $renderValues[$blockID];
                      $renderValues[$blockID] = ' ';
                      break;
                  }
              }
          }
      }
  
  }
  </code></pre>
  
  <p>The array renderBlocksPropsByOrder has the configuration of each field:</p>
  
  <pre><code>(
  [0] =&gt; Array
      (
          [blockID] =&gt; 0
          [isBlankSensitive] =&gt; 1
          [blankSensitivityDirection] =&gt; down
      )
  
  [1] =&gt; Array
      (
          [blockID] =&gt; 1
          [isBlankSensitive] =&gt; 1
          [blankSensitivityDirection] =&gt; up
      )
  
  [2] =&gt; Array
      (
          [blockID] =&gt; 2
          [isBlankSensitive] =&gt; 0
          [blankSensitivityDirection] =&gt; ''
      )
  
  [3] =&gt; Array
      (
          [blockID] =&gt; 3
          [isBlankSensitive] =&gt; 1
          [blankSensitivityDirection] =&gt; up
      )
  
  [4] =&gt; Array
      (
          [blockID] =&gt; 4
          [isBlankSensitive] =&gt; 1
          [blankSensitivityDirection] =&gt; up
      )
  
  [5] =&gt; Array
      (
          [blockID] =&gt; 5
          [isBlankSensitive] =&gt; 1
          [blankSensitivityDirection] =&gt; up
      )
  
  [6] =&gt; Array
      (
          [blockID] =&gt; 6
          [isBlankSensitive] =&gt; 1
          [blankSensitivityDirection] =&gt; up
      )
  
  )
  </code></pre>
  
  <p>RenderValues has the value of each field. Initial renderValues array looks like:</p>
  
  <pre><code>(
      [0] =&gt; Dan
      [1] =&gt; 
      [2] =&gt; 
      [3] =&gt; 
      [4] =&gt; grwgwr@geffw.com
      [5] =&gt; 12 jal
      [6] =&gt; NYC, NY, 12345
  )
  </code></pre>
  
  <p>I've been spending a long time on this really any help that can help me go forward will be very, very appreciated.</p>
  
  <p>If this way proves to be too complex, I'll take any suggestions for an alternative, user-friendly way of configuring the business cards.</p>