<!DOCTYPE html>
<html ng-app='app'>
<head>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/3.1.1/ui-grid.css" rel="stylesheet" />

    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
    <link href="main.css" rel="stylesheet" />

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.3/jquery.min.js"></script>
    <script src="https://code.angularjs.org/1.5.5/angular.min.js"></script>
    <script src="https://code.angularjs.org/1.5.5/angular-route.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/3.1.1/ui-grid.min.js"></script>
    <script src="https://code.angularjs.org/1.5.5/angular-touch.min.js"></script>
    <script src="https://code.angularjs.org/1.5.5/angular-animate.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
    <script src="app.js"></script>

    <title>Shoplify</title>
</head>
<body>
    <h3>Select your Items</h3>
    <div ng-controller="MainController">
        <table>
            <tr>
                <td>
                    <div ui-grid="gridOptions" ui-grid-pagination class="grid"></div>
                    <div id="divButtons">
                        <input type="button" id="btnOrder" class="btn btn-success" ng-disabled="isDisabled" ng-model="isDisabled" ng-click="placeOrder()" value="Place Order">
                        <input type="button" id="btnClear" class="btn btn-danger" ng-click="clearOrder()"  value="Clear Orders">
                    </div>
                </td>
                <td>
                    <h3><u>Order details:</u></h3>
                    <p>{{itemCount}}</p>
                    <div ng-repeat="package in packages track by $index ">
                        <br />
                        <p>{{ package.name }}</p>
                       <p></p>

                        <p>Items    -{{ package.itemNames }}</p>
                        <p>Total Weight -{{ package.weight }}g</p>
                        <p>Total Price  -{{ package.price| currency }}</p>
                        <p>Courier Price    -{{ package.shipping_cost | currency}}</p>

                    </div>
                </td>
            </tr>
        </table>
    </div>
</body>
</html>
var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.pagination', 'ui.grid.edit']);

app.controller('MainController', ['$scope', '$http', function($scope, $http) {

  //get data
  $scope.items = $http.get('products.json')
    .success(function(myData) {
      $scope.gridOptions.data = myData.Items;
    });

  // set the grid data
  $scope.gridOptions = {
    paginationPageSizes: [15, 30, 60],
    paginationPageSize: 15,
    columnDefs: [{
      field: 'Name'
    }, {
      field: 'Price',
      displayName: 'Price($)'
    }, {
      field: 'Weight',
      displayName: 'Weight(g)'
    }, {
      field: 'active',
      displayName: '',
      type: 'boolean',

      cellTemplate: '<input type="checkbox" id="cbox" ng-checked=row.entity.active ng-model="row.entity.active" ng-click="grid.appScope.toggleActive(row,row.entity)">'
    }]
  };

  $scope.gridOptions.onRegisterApi = function(gridApi) {
    $scope.gridApi2 = gridApi;
  };


  // variable initiation
  $scope.isDisabled = true;
  $scope.selectedItems = [];
  $scope.cartItems = [];
  $scope.package = [];
  $scope.packages = [];
  initiatePackage();


  function initiatePackage() {
    return $scope.package = {
      name: 'Package',
      items: [], //holds the items
      itemNames: '',
      weight: 0, //total weight of all items in the package
      weight_capacity: 5000,
      price: 0, //total price of all items in the package
      price_capacity: 250,
      shipping_cost: 0,
      cost_per_gram: 20
    };
  }

  // checkbox click event -- add or remove item on select/deselect
  $scope.toggleActive = function(r, row) {

    if (row.active) {
      if (row.Price <= 250) {
        var item = [];
        item.name = row.Name;
        item.weight = parseInt(row.Weight);
        item.price = parseInt(row.Price);
        $scope.cartItems.push(item);
        if ($scope.selectedItems.length === 0)
          $scope.isDisabled = false;
        $scope.selectedItems.push(row);

      }
    } else {
      $scope.removeItem(row.Name);
    }
  };

  $scope.clearCart = function() {
    $scope.cartItems = [];
  };

  // deselected item
  $scope.removeItem = function(name) {
    indexes = $.map($scope.cartItems, function(obj, index) {
      if (obj.name == name) {
        return index;
      }
    });
    $scope.cartItems.splice(indexes[0], 1);
  };

  //place order
  var count = $scope.packages.length;

  $scope.placeOrder = function() {
    $scope.itemCount = "Items count: - " + ($scope.cartItems.length);
    $scope.packages = getPackages($scope.cartItems);
    $scope.isDisabled = true;
  };

  // Clear Order Button event
  $scope.clearOrder = function() {
    if (confirm('Are you sure?')) {
      $scope.clearCart();
      $scope.packages = [];

      angular.forEach($scope.selectedItems, function(val, i) {
        val.active = false;
      });
      $scope.selectedItems = [];
      $scope.isDisabled = true;
      $scope.itemCount = '';
      count = $scope.packages.length;
    }
  };

  //Process the items into packages
  function getPackages(items) {
    initiatePackage();
    angular.forEach(items, function(item, key) {

      if ($scope.package.items.length === 0) {
        $scope.packages.push($scope.package);
        count++;
        $scope.package.name = $scope.package.name + ' ' + count;
      }

      var added = false;

      if (canHold(item)) {

        $scope.package.items.push(item);
        $scope.package.itemNames === "" ? $scope.package.itemNames = '' : $scope.package.itemNames = $scope.package.itemNames + ',';
        $scope.package.itemNames += item.name;
        $scope.package.weight += item.weight;
        $scope.package.price += item.price;
        $scope.package.price_capacity -= item.price;
        $scope.package.shipping_cost = calculateShipping($scope.package.weight);
        $scope.package.cost_per_gram = $scope.package.shipping_cost / $scope.package.weight;

        added = true;

      }

      if (!added) {
        //Time to open a new BOX!
        initiatePackage();
        count++;
        $scope.package.items.push(item);
        $scope.package.itemNames === "" ? $scope.package.itemNames = '' : $scope.package.itemNames = $scope.package.itemNames + ',';
        $scope.package.itemNames += item.name;
        $scope.package.name = $scope.package.name + ' ' + count;
        $scope.package.weight += item.weight;
        $scope.package.price += item.price;
        $scope.package.price_capacity -= item.price;
        $scope.package.shipping_cost = calculateShipping($scope.package.weight);
        $scope.package.cost_per_gram = $scope.package.shipping_cost / $scope.package.weight;
        $scope.packages.push($scope.package);

      }
    });

    //calculate the min number of packing we need
    ////if (typeof ($scope.packages) !== "undefined") {
    ////    var total_boxes = $scope.packages.length;
    ////    if (total_boxes > 0) {

    ////        //clear the box contents
    ////        //// resetPackages($scope.packages);
    ////        //put the items back in the packages balancing their weight as equally as possible
    ////        //// balanceWeight();
    ////    }
    ////}

    return $scope.packages;
  }

  // validate the item can keep it in the same package
  function canHold(item) {
    var canhold = false;
    if (($scope.package.price_capacity >= item.price) && $scope.package.weight_capacity >= item.weight) {
      canhold = true;
    }
    return canhold;
  }

  //Calculate shipping cost
  function calculateShipping(weight) {
    if (weight >= 0 && weight <= 200) {
      return 5;
    } else if (weight >= 201 && weight <= 500) {
      return 10;
    } else if (weight >= 501 && weight <= 1000) {
      return 15;
    } else if (weight >= 1001 && weight <= 5000) {
      return 20;
    }
  }

  //Reset Package before balancing the weight distribution
  function resetPackages(p) {
    var count = $scope.packages.length;

    for (var i = 0; i < count; i++) {
      $scope.packages[i] = initiatePackage();

    }

  }

  function balanceWeight() {
    var count = $scope.packages.length;
    $scope.cartItems.sort(function sortCart(a, b) {
      if (a.weight == b.weight) {
        return 0;
      } else if (a.weight < b.weight) {
        return +1;
      } else {
        return -1;
      }
    });

    for (var i = 0; i < count; i++) {

      $scope.package = $scope.packages[i];
      $scope.cartItems.forEach(function(item) {
        if (canHold(item)) {
          $scope.package.items.push(item);
          $scope.package.itemNames === "" ? $scope.package.itemNames = '' : $scope.package.itemNames = $scope.package.itemNames + ',';
          $scope.package.itemNames += item.name;
          $scope.package.weight += item.weight;
          $scope.package.price += item.price;
          $scope.package.price_capacity -= item.price;
          $scope.package.shipping_cost = calculateShipping($scope.package.weight);
          $scope.package.cost_per_gram = $scope.package.shipping_cost / $scope.package.weight;

        } else {
          sortByCost();
        }
      });

    }
  }

  function sortByCost() {
    $scope.packages.sort(function sortPackages(a, b) {

      if (a.cost_per_gram == b.cost_per_gram) {
        return 0;
      } else if (a.cost_per_gram < b.cost_per_gram) {
        return +1;
      } else {
        return -1;
      }

    });
  }




}]);
.grid
{
    width: 500px;
    padding: 15px;
    border:medium;
    margin: 30px;
    height:525px;
     
    padding-top: 0px;
    margin-top: 10px;
    
    margin-bottom: 3px;


}

.button
{
    margin-left: 30px;
}

#divButtons
{
    margin-left: 30px;
}


p
{
    margin-left: 30px;
}

body h1
{
    /*color:#fff;*/
    font-size: 35px;
    /*font-family:'Cookie', cursive;*/
    font-weight: normal;
    line-height: 1;
    text-shadow: 0 3px 0 rgba(0,0,0,0.1);
}

body
{
    /*background-color: #61a1bc;*/
    border-radius: 2px;
    box-shadow: 0 1px 1px #ccc;
    /*width: 400px;*/
    /*padding: 35px 60px;*/
    margin: 80px auto;
}

/*body p
    {
        color:#fff;
    }*/
 {"Items":
 [
    {
      "Name": "Item 1",
      "Price": "10",
      "Weight": "200"
	
    },
    {
      "Name": "Item 2",
      "Price": "100",
      "Weight": "20"
    },
    {
      "Name": "Item 3",
      "Price": "30",
      "Weight": "300"
    },
    {
      "Name": "Item 4",
      "Price": "20",
      "Weight": "500"
    },
    {
      "Name": "Item 5",
      "Price": "30",
      "Weight": "250"
    },
    {
      "Name": "Item 6",
      "Price": "40",
      "Weight": "10"
    },
    {
      "Name": "Item 7",
      "Price": "200",
      "Weight": "10"
    },
    {
      "Name": "Item 8",
      "Price": "120",
      "Weight": "500"
    },
    {
      "Name": "Item 9",
      "Price": "130",
      "Weight": "790"
    },
    {
      "Name": "Item 10",
      "Price": "20",
      "Weight": "100"
    },
    {
      "Name": "Item 11",
      "Price": "10",
      "Weight": "340"
    },
    {
      "Name": "Item 12",
      "Price": "4",
      "Weight": "800"
    },
    {
      "Name": "Item 13",
      "Price": "5",
      "Weight": "200"
    },
    {
      "Name": "Item 14",
      "Price": "240",
      "Weight": "20"
    },
    {
      "Name": "Item 15",
      "Price": "123",
      "Weight": "700"
    },
    {
      "Name": "Item 16",
      "Price": "245",
      "Weight": "10"
    },
    {
      "Name": "Item 17",
      "Price": "230",
      "Weight": "20"
    },
    {
      "Name": "Item 18",
      "Price": "110",
      "Weight": "200"
    },
    {
      "Name": "Item 19",
      "Price": "45",
      "Weight": "200"
    },
    {
      "Name": "Item 20",
      "Price": "67",
      "Weight": "20"
    },
    {
      "Name": "Item 21",
      "Price": "88",
      "Weight": "300"
    },
    {
      "Name": "Item 22",
      "Price": "10",
      "Weight": "500"
    },
    {
      "Name": "Item 23",
      "Price": "17",
      "Weight": "250"
    },
    {
      "Name": "Item 24",
      "Price": "19",
      "Weight": "10"
    },
    {
      "Name": "Item 25",
      "Price": "89",
      "Weight": "10"
    },
    {
      "Name": "Item 26",
      "Price": "45",
      "Weight": "500"
    },
    {
      "Name": "Item 27",
      "Price": "99",
      "Weight": "790"
    },
    {
      "Name": "Item 28",
      "Price": "125",
      "Weight": "100"
    },
    {
      "Name": "Item 29",
      "Price": "198",
      "Weight": "340"
    },
    {
      "Name": "Item 30",
      "Price": "220",
      "Weight": "800"
    },
    {
      "Name": "Item 31",
      "Price": "249",
      "Weight": "200"
    },
    {
      "Name": "Item 32",
      "Price": "230",
      "Weight": "20"
    },
    {
      "Name": "Item 33",
      "Price": "190",
      "Weight": "700"
    },
    {
      "Name": "Item 34",
      "Price": "45",
      "Weight": "10"
    },
    {
      "Name": "Item 35",
      "Price": "12",
      "Weight": "20"
    },
    {
      "Name": "Item 36",
      "Price": "5",
      "Weight": "200"
    },
    {
      "Name": "Item 37",
      "Price": "2",
      "Weight": "200"
    },
    {
      "Name": "Item 38",
      "Price": "90",
      "Weight": "20"
    },
    {
      "Name": "Item 39",
      "Price": "12",
      "Weight": "300"
    },
    {
      "Name": "Item 40",
      "Price": "167",
      "Weight": "500"
    },
    {
      "Name": "Item 41",
      "Price": "12",
      "Weight": "250"
    },
    {
      "Name": "Item 42",
      "Price": "8",
      "Weight": "10"
    },
    {
      "Name": "Item 43",
      "Price": "2",
      "Weight": "10"
    },
    {
      "Name": "Item 44",
      "Price": "9",
      "Weight": "500"
    },
    {
      "Name": "Item 45",
      "Price": "210",
      "Weight": "790"
    },
    {
      "Name": "Item 46",
      "Price": "167",
      "Weight": "100"
    },
    {
      "Name": "Item 47",
      "Price": "23",
      "Weight": "340"
    },
    {
      "Name": "Item 48",
      "Price": "190",
      "Weight": "800"
    },
    {
      "Name": "Item 49",
      "Price": "199",
      "Weight": "200"
    },
    {
      "Name": "Item 50",
      "Price": "12",
      "Weight": "20"
    }
  ]
  }
This solution in pure Front-End that solves the following problem.
A company sells hundreds of products on-line and people place orders from all over the world, just like eBay. Each item has a different weight and price.
And each order can be a combination of different number of items. Now each of these orders are to be put into different packages and sent to the courier company for delivery.
But there are certain rules while splitting items into packages, they are as below:
1. If the cost of all the items in an order is more than $250, split those items into multiple packages, otherwise one package would be enough.
2. If the items in the same order are split into multiple packages, then the weight of the packages should be equally distributed over the packages to save courier charges.
3. While splitting, NO PACKAGE can have a total price above $250
Create a page (You may want to use JQuery/Angular, HTML5, bootstrap) which has the following:
1.	A simple vertical list of items (in the format Name - price - weight), with a check box next to item
2.	A button saying "Place order"
When the user clicks on "Place order", the selected items should be submitted to the same page without refreshing the page and the above splitting rules should be applied to divide this particular order into multiple packages, and display the output result on the same page. Below is a sample output on how it should look like:
This order has following packages:
 Package 1 
Items - Item 1, Item 3, item 7
Total weight 	- 510g
Total price 	- $240  
Courier price 	- $15
Package 2 
Items -  Item 4, Item 6, item 2
Total weight 	- 530g
Total price 	- $160
Courier price 	- $15
Note : Items and courier prices are in the Test_info.xls attached, You may want to use JQuery/AngularJS, HTML5, Bootstrap as frontend. No Backend End code required, You may want to load the excel file using the front-end itself, you may want to convert the data to csv format if neccesary for loading purposes. The application will be marked based on the functionality, modularity, coding standard, the approach taken to reduce lines of codes and best practice/approach/plugins.